New upstream version 0.13.1~dfsg1
authorJaromír Mikeš <mira.mikes@seznam.cz>
Mon, 21 Nov 2016 08:32:09 +0000 (09:32 +0100)
committerJaromír Mikeš <mira.mikes@seznam.cz>
Mon, 21 Nov 2016 08:32:09 +0000 (09:32 +0100)
142 files changed:
ChangeLog
Makefile.am
src/core/channel.cpp
src/core/channel.h
src/core/conf.cpp
src/core/const.h
src/core/dataStorageIni.cpp
src/core/dataStorageJson.cpp
src/core/graphics.cpp
src/core/graphics.h
src/core/init.cpp
src/core/kernelAudio.cpp
src/core/kernelAudio.h
src/core/kernelMidi.cpp
src/core/kernelMidi.h
src/core/midiChannel.cpp
src/core/midiChannel.h
src/core/midiMapConf.cpp
src/core/midiMapConf.h
src/core/mixer.cpp
src/core/mixer.h
src/core/mixerHandler.cpp
src/core/mixerHandler.h
src/core/patch.cpp
src/core/patch.h
src/core/patch_DEPR_.cpp
src/core/plugin.cpp
src/core/pluginHost.cpp
src/core/pluginHost.h
src/core/recorder.cpp
src/core/recorder.h
src/core/sampleChannel.cpp
src/core/sampleChannel.h
src/core/wave.cpp
src/core/waveFx.cpp
src/core/waveFx.h
src/glue/channel.cpp
src/glue/channel.h
src/glue/glue.cpp [deleted file]
src/glue/glue.h [deleted file]
src/glue/io.cpp [new file with mode: 0644]
src/glue/io.h [new file with mode: 0644]
src/glue/main.cpp [new file with mode: 0644]
src/glue/main.h [new file with mode: 0644]
src/glue/storage.cpp
src/glue/storage.h
src/gui/dialogs/gd_about.cpp
src/gui/dialogs/gd_about.h
src/gui/dialogs/gd_actionEditor.cpp
src/gui/dialogs/gd_actionEditor.h
src/gui/dialogs/gd_beatsInput.cpp
src/gui/dialogs/gd_bpmInput.cpp
src/gui/dialogs/gd_browser.cpp
src/gui/dialogs/gd_config.cpp
src/gui/dialogs/gd_config.h
src/gui/dialogs/gd_devInfo.cpp
src/gui/dialogs/gd_editor.cpp
src/gui/dialogs/gd_editor.h
src/gui/dialogs/gd_keyGrabber.cpp
src/gui/dialogs/gd_mainWindow.cpp
src/gui/dialogs/gd_mainWindow.h
src/gui/dialogs/gd_midiInput.cpp
src/gui/dialogs/gd_midiInput.h
src/gui/dialogs/gd_midiOutput.cpp
src/gui/dialogs/gd_pluginChooser.cpp
src/gui/dialogs/gd_pluginList.cpp
src/gui/dialogs/gd_pluginWindow.cpp
src/gui/dialogs/gd_pluginWindowGUI.cpp
src/gui/dialogs/gd_warnings.h
src/gui/elems/actionEditor.cpp [new file with mode: 0644]
src/gui/elems/actionEditor.h [new file with mode: 0644]
src/gui/elems/baseActionEditor.cpp [new file with mode: 0644]
src/gui/elems/baseActionEditor.h [new file with mode: 0644]
src/gui/elems/channel.cpp [new file with mode: 0644]
src/gui/elems/channel.h [new file with mode: 0644]
src/gui/elems/channelButton.cpp [new file with mode: 0644]
src/gui/elems/channelButton.h [new file with mode: 0644]
src/gui/elems/envelopeEditor.cpp [new file with mode: 0644]
src/gui/elems/envelopeEditor.h [new file with mode: 0644]
src/gui/elems/ge_actionChannel.cpp [deleted file]
src/gui/elems/ge_actionChannel.h [deleted file]
src/gui/elems/ge_actionWidget.cpp [deleted file]
src/gui/elems/ge_actionWidget.h [deleted file]
src/gui/elems/ge_browser.cpp
src/gui/elems/ge_channel.cpp [deleted file]
src/gui/elems/ge_channel.h [deleted file]
src/gui/elems/ge_channelButton.cpp [deleted file]
src/gui/elems/ge_channelButton.h [deleted file]
src/gui/elems/ge_column.cpp
src/gui/elems/ge_column.h
src/gui/elems/ge_controller.cpp
src/gui/elems/ge_envelopeChannel.cpp [deleted file]
src/gui/elems/ge_envelopeChannel.h [deleted file]
src/gui/elems/ge_keyboard.cpp
src/gui/elems/ge_keyboard.h
src/gui/elems/ge_midiChannel.cpp [deleted file]
src/gui/elems/ge_midiChannel.h [deleted file]
src/gui/elems/ge_midiIoTools.cpp
src/gui/elems/ge_midiIoTools.h
src/gui/elems/ge_mixed.cpp
src/gui/elems/ge_mixed.h
src/gui/elems/ge_modeBox.cpp
src/gui/elems/ge_muteChannel.cpp [deleted file]
src/gui/elems/ge_muteChannel.h [deleted file]
src/gui/elems/ge_pianoRoll.cpp [deleted file]
src/gui/elems/ge_pianoRoll.h [deleted file]
src/gui/elems/ge_sampleChannel.cpp [deleted file]
src/gui/elems/ge_sampleChannel.h [deleted file]
src/gui/elems/ge_status.cpp
src/gui/elems/ge_waveTools.cpp
src/gui/elems/ge_waveform.cpp
src/gui/elems/ge_waveform.h
src/gui/elems/ge_window.cpp
src/gui/elems/ge_window.h
src/gui/elems/midiChannel.cpp [new file with mode: 0644]
src/gui/elems/midiChannel.h [new file with mode: 0644]
src/gui/elems/muteEditor.cpp [new file with mode: 0644]
src/gui/elems/muteEditor.h [new file with mode: 0644]
src/gui/elems/noteEditor.cpp [new file with mode: 0644]
src/gui/elems/noteEditor.h [new file with mode: 0644]
src/gui/elems/pianoItem.cpp [new file with mode: 0644]
src/gui/elems/pianoItem.h [new file with mode: 0644]
src/gui/elems/pianoRoll.cpp [new file with mode: 0644]
src/gui/elems/pianoRoll.h [new file with mode: 0644]
src/gui/elems/sampleChannel.cpp [new file with mode: 0644]
src/gui/elems/sampleChannel.h [new file with mode: 0644]
src/main.cpp
src/utils/fs.cpp [new file with mode: 0644]
src/utils/fs.h [new file with mode: 0644]
src/utils/gui.cpp [new file with mode: 0644]
src/utils/gui.h [new file with mode: 0644]
src/utils/gui_utils.cpp [deleted file]
src/utils/gui_utils.h [deleted file]
src/utils/log.cpp
src/utils/log.h
src/utils/string.cpp
src/utils/string.h
src/utils/utils.cpp [deleted file]
src/utils/utils.h [deleted file]
tests/patch.cpp
tests/pluginHost.cpp
tests/utils.cpp

index abcbc3fe01d5deff77c42bfd8539b223971bef79..22878ce9131430c01c1ced5ea71a5543464490d4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
-0.13.0 ---
+0.13.1 --- 2016 . 11 . 16
+- Input MIDI to MIDI channels/plugins
+- Refinements to show/hide 'R' button's dynamics
+- Increase piano roll items' height
+- Set input volume to max by default
+- Start live-recorded sample channels right away
+- Avoid potential crashes when loading samples on running channels
+- Generate metronome during output post-processing
+- Better widgets' layout in Sample Editor
+- Lots of source code optimizations and cleanups
+- Fix inverted 'R' button's status (GitHub #94)
+- Better handling of 'R' button's status when the sequencer is off (GitHub #95)
+- Fix non-playing samples if live-recorded and 'R' button is on (GitHub #93)
+- Reset button statuses once channels have been freed (GitHub #100)
+- Fix missing ASIO and WASAPI APIs on Windows (GitHub #96)
+- Missing RtMidi libs on Linux (GitHub #102)
+- Fix fade-in/fade-out editing not triggering alert on save (GitHub #101)
+
+
+0.13.0 --- 2016 . 09 . 20
 - Deep file browser refactoring
 - Save browser's scroll position and last item selected on opening
 - Load patches/projects/samples on double click
 - Update JUCE to version 4.2.3
 - Don't include JUCE on tests without VST support (GitHub #75)
 - Fix compilation errors on GCC 6 (GitHub #82)
+- Fix includes on OSX (GitHub #92)
 - Fix wrong channel's actions count that prevented "R" button to be toggled
   properly
 - Fixed a bug that prevented actions on frame 0 to being properly reproduced
+- Make Recorder a proper class
+- Better naming convention for ActionEditor's children classes
+- Source code reorganization
 
 
 0.12.2 --- 2016 . 06 . 02
index a78f094e70b5662c818feb0178201faf888a9613..7990158a465d0abdd6c899e01c83f81e99f15587 100644 (file)
@@ -47,8 +47,10 @@ src/core/dataStorageIni.h                 \
 src/core/dataStorageIni.cpp            \
 src/core/dataStorageJson.h                \
 src/core/dataStorageJson.cpp           \
-src/glue/glue.h                        \
-src/glue/glue.cpp                      \
+src/glue/main.h                        \
+src/glue/main.cpp                      \
+src/glue/io.h                          \
+src/glue/io.cpp                        \
 src/glue/storage.h                     \
 src/glue/storage.cpp                   \
 src/glue/channel.h                     \
@@ -89,10 +91,10 @@ src/gui/dialogs/gd_pluginChooser.h     \
 src/gui/dialogs/gd_pluginChooser.cpp   \
 src/gui/elems/ge_column.h              \
 src/gui/elems/ge_column.cpp            \
-src/gui/elems/ge_sampleChannel.h       \
-src/gui/elems/ge_sampleChannel.cpp     \
-src/gui/elems/ge_midiChannel.h         \
-src/gui/elems/ge_midiChannel.cpp       \
+src/gui/elems/sampleChannel.h          \
+src/gui/elems/sampleChannel.cpp        \
+src/gui/elems/midiChannel.h            \
+src/gui/elems/midiChannel.cpp          \
 src/gui/elems/ge_midiIoTools.h         \
 src/gui/elems/ge_midiIoTools.cpp       \
 src/gui/elems/ge_mixed.h               \
@@ -101,18 +103,22 @@ src/gui/elems/ge_waveform.h            \
 src/gui/elems/ge_waveform.cpp          \
 src/gui/elems/ge_browser.h                      \
 src/gui/elems/ge_browser.cpp           \
-src/gui/elems/ge_actionWidget.h        \
-src/gui/elems/ge_actionWidget.cpp      \
-src/gui/elems/ge_envelopeChannel.h     \
-src/gui/elems/ge_envelopeChannel.cpp   \
-src/gui/elems/ge_pianoRoll.h                  \
-src/gui/elems/ge_pianoRoll.cpp         \
-src/gui/elems/ge_channel.h             \
-src/gui/elems/ge_channel.cpp           \
-src/gui/elems/ge_muteChannel.h         \
-src/gui/elems/ge_muteChannel.cpp       \
-src/gui/elems/ge_actionChannel.h       \
-src/gui/elems/ge_actionChannel.cpp     \
+src/gui/elems/baseActionEditor.h       \
+src/gui/elems/baseActionEditor.cpp     \
+src/gui/elems/envelopeEditor.h         \
+src/gui/elems/envelopeEditor.cpp       \
+src/gui/elems/pianoRoll.h              \
+src/gui/elems/pianoRoll.cpp            \
+src/gui/elems/noteEditor.h                      \
+src/gui/elems/noteEditor.cpp           \
+src/gui/elems/pianoItem.h              \
+src/gui/elems/pianoItem.cpp            \
+src/gui/elems/channel.h                \
+src/gui/elems/channel.cpp              \
+src/gui/elems/muteEditor.h             \
+src/gui/elems/muteEditor.cpp           \
+src/gui/elems/actionEditor.h           \
+src/gui/elems/actionEditor.cpp         \
 src/gui/elems/ge_window.h                               \
 src/gui/elems/ge_window.cpp            \
 src/gui/elems/ge_status.h              \
@@ -125,17 +131,17 @@ src/gui/elems/ge_modeBox.h             \
 src/gui/elems/ge_modeBox.cpp           \
 src/gui/elems/ge_controller.h          \
 src/gui/elems/ge_controller.cpp        \
-src/gui/elems/ge_channelButton.h       \
-src/gui/elems/ge_channelButton.cpp     \
+src/gui/elems/channelButton.h          \
+src/gui/elems/channelButton.cpp        \
 src/gui/elems/ge_pluginBrowser.h       \
 src/gui/elems/ge_pluginBrowser.cpp     \
 src/utils/log.h                        \
 src/utils/log.cpp                      \
-src/utils/gui_utils.h                  \
-src/utils/gui_utils.cpp                \
+src/utils/gui.h                        \
+src/utils/gui.cpp                      \
 src/utils/gvector.h                    \
-src/utils/utils.h                      \
-src/utils/utils.cpp                    \
+src/utils/fs.h                         \
+src/utils/fs.cpp                       \
 src/utils/string.h                     \
 src/utils/string.cpp
 
@@ -176,13 +182,13 @@ giada_CPPFLAGS +=                          \
   -DJUCE_PLUGINHOST_VST=1                  \
   -DJUCE_PLUGINHOST_VST3=0                 \
   -DJUCE_PLUGINHOST_AU=0
-giada_CXXFLAGS += -Wno-error=misleading-indentation
 endif
 
 if LINUX
 giada_SOURCES += src/deps/rtaudio-mod/RtAudio.h src/deps/rtaudio-mod/RtAudio.cpp
-# mute rtAudio error on variable length array
-giada_CXXFLAGS += -Wno-error=vla
+# -Wno-error=vla: mute rtAudio error on variable length array
+# -Wno-error=misleading-indentation: mute JUCE warnings on GCC6
+giada_CXXFLAGS += -Wno-error=vla -Wno-error=misleading-indentation
 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 \
@@ -190,7 +196,28 @@ giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
 endif
 
 if WINDOWS
-giada_LDADD = -lrtaudio -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \
+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
+# -Wno-error=misleading-indentation: mute JUCE warnings on GCC6
+# -Wno-error=unused-but-set-variable: silence ASIO errors
+giada_CXXFLAGS +=                  \
+-Wno-error=misleading-indentation  \
+-Wno-error=unused-but-set-variable
+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 -lpthreadGC2 -ljansson \
   -limm32 -lglu32 -lshell32 -lversion -lopengl32 -loleaut32 -lshlwapi -lcomdlg32
@@ -203,8 +230,9 @@ if OSX
 # export CXXFLAGS="-m32"
 # export LDFLAGS="-m32"
 # -ObjC++: Juce requires to build some Objective C code
+# -Wno-unknown-pragmas: shut up Juce even more
 giada_SOURCES += src/utils/cocoa.mm src/utils/cocoa.h
-giada_CXXFLAGS += -ObjC++
+giada_CXXFLAGS += -ObjC++ -Wno-unknown-pragmas
 giada_LDADD = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \
        -lsamplerate -ljansson
 giada_LDFLAGS = -framework CoreAudio -framework Cocoa -framework Carbon \
@@ -234,10 +262,10 @@ src/core/wave.cpp            \
 src/core/midiMapConf.cpp     \
 src/core/patch.cpp           \
 src/core/plugin.cpp          \
-src/core/pluginHost.cpp      \
 src/core/dataStorageIni.cpp  \
 src/core/dataStorageJson.cpp \
-src/utils/utils.cpp          \
+src/utils/fs.cpp             \
+src/utils/string.cpp         \
 src/utils/log.cpp
 
 if WITH_VST
index 1a3204a12c718838d6cce4a28b20f6e71469e3ca..bcbafeb716a5d811a962c73179d485dc0500f205 100644 (file)
@@ -28,7 +28,7 @@
 
 
 #include "../utils/log.h"
-#include "../gui/elems/ge_channel.h"
+#include "../gui/elems/channel.h"
 #include "channel.h"
 #include "pluginHost.h"
 #include "plugin.h"
 #include "midiMapConf.h"
 
 
+extern Recorder   G_Recorder;
+extern KernelMidi G_KernelMidi;
+
+
 Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf)
 #if defined(WITH_VST)
-: pluginHost(NULL),
+: pluginHost(nullptr),
 #else
 :
 #endif
@@ -65,13 +69,15 @@ Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf)
   mute           (false),
   solo           (false),
   hasActions     (false),
+  armed          (false),
   recStatus      (REC_STOPPED),
-  vChan          (NULL),
-  guiChannel     (NULL),
+  vChan          (nullptr),
+  guiChannel     (nullptr),
   midiIn         (true),
   midiInKeyPress (0x0),
   midiInKeyRel   (0x0),
   midiInKill     (0x0),
+  midiInArm      (0x0),
   midiInVolume   (0x0),
   midiInMute     (0x0),
   midiInSolo     (0x0),
@@ -82,7 +88,7 @@ Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf)
 {
   vChan = (float *) malloc(bufferSize * sizeof(float));
        if (!vChan)
-               gLog("[Channel::allocVchan] unable to alloc memory for vChan\n");
+               gu_log("[Channel::allocVchan] unable to alloc memory for vChan\n");
        memset(vChan, 0, bufferSize * sizeof(float));
 }
 
@@ -119,6 +125,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
   midiInKeyPress  = src->midiInKeyPress;
   midiInKeyRel    = src->midiInKeyRel;
   midiInKill      = src->midiInKill;
+  midiInArm       = src->midiInArm;
   midiInVolume    = src->midiInVolume;
   midiInMute      = src->midiInMute;
   midiInSolo      = src->midiInSolo;
@@ -137,11 +144,11 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
 
   /* clone actions */
 
-  for (unsigned i=0; i<recorder::global.size(); i++) {
-    for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-      recorder::action *a = recorder::global.at(i).at(k);
+  for (unsigned i=0; i<G_Recorder.global.size(); i++) {
+    for (unsigned k=0; k<G_Recorder.global.at(i).size(); k++) {
+      Recorder::action *a = G_Recorder.global.at(i).at(k);
       if (a->chan == src->index)
-        recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
+        G_Recorder.rec(index, a->type, a->frame, a->iValue, a->fValue);
     }
   }
 }
@@ -152,7 +159,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
 
 void Channel::sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg)
 {
-       gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
+       gu_log("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
                learn, msg.channel, msg.value, msg.offset);
 
        /* isolate 'channel' from learnt message and offset it as requested by 'nn'
@@ -164,7 +171,7 @@ void Channel::sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg
         * send it. */
 
        out |= msg.value | (msg.channel << 24);
-       kernelMidi::send(out);
+       G_KernelMidi.send(out);
 }
 
 
@@ -220,6 +227,7 @@ int Channel::writePatch(int i, bool isProject, Patch *patch)
        pch.midiInKeyPress  = midiInKeyPress;
        pch.midiInKeyRel    = midiInKeyRel;
        pch.midiInKill      = midiInKill;
+       pch.midiInArm       = midiInArm;
        pch.midiInVolume    = midiInVolume;
        pch.midiInMute      = midiInMute;
        pch.midiInSolo      = midiInSolo;
@@ -228,9 +236,9 @@ int Channel::writePatch(int i, bool isProject, Patch *patch)
        pch.midiOutLmute    = midiOutLmute;
        pch.midiOutLsolo    = midiOutLsolo;
 
-       for (unsigned i=0; i<recorder::global.size(); i++) {
-               for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-                       recorder::action *action = recorder::global.at(i).at(k);
+       for (unsigned i=0; i<G_Recorder.global.size(); i++) {
+               for (unsigned k=0; k<G_Recorder.global.at(i).size(); k++) {
+                       Recorder::action *action = G_Recorder.global.at(i).at(k);
                        if (action->chan == index) {
                                Patch::action_t pac;
                                pac.type   = action->type;
@@ -296,7 +304,7 @@ int Channel::readPatch(const string &path, int i, Patch *patch,
 
        for (unsigned k=0; k<pch->actions.size(); k++) {
                Patch::action_t *ac = &pch->actions.at(k);
-               recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue);
+               G_Recorder.rec(index, ac->type, ac->frame, ac->iValue, ac->fValue);
        }
 
 #ifdef WITH_VST
@@ -305,7 +313,7 @@ int Channel::readPatch(const string &path, int i, Patch *patch,
                Patch::plugin_t *ppl = &pch->plugins.at(k);
                Plugin *plugin = pluginHost->addPlugin(ppl->path, PluginHost::CHANNEL,
       pluginMutex, this);
-               if (plugin != NULL) {
+               if (plugin != nullptr) {
                        plugin->setBypass(ppl->bypass);
                        for (unsigned j=0; j<ppl->params.size(); j++)
                                plugin->setParameter(j, ppl->params.at(j));
@@ -375,9 +383,36 @@ void Channel::sendMidiLplay()
 /* -------------------------------------------------------------------------- */
 
 
+void Channel::receiveMidi(uint32_t msg)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+
 #ifdef WITH_VST
+
+juce::MidiBuffer &Channel::getPluginMidiEvents()
+{
+  return midiBuffer;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::clearMidiBuffer()
+{
+  midiBuffer.clear();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void Channel::setPluginHost(PluginHost *pluginHost)
 {
   this->pluginHost = pluginHost;
 }
+
 #endif
index e0ee899032d1e9dd819e6efe196e554a3c5889fb..df9fe64694f11d9f0f12707331844c8d98aa8c12 100644 (file)
 
 
 #include <vector>
-#include "../utils/utils.h"
+#include <pthread.h>
 #include "midiMapConf.h"
-#include "const.h"
 #include "recorder.h"
 
 #ifdef WITH_VST
        #include "../deps/juce/config.h"
 #endif
 
+
 using std::vector;
 using std::string;
 
@@ -91,12 +91,6 @@ public:
 
        virtual void copy(const Channel *src, pthread_mutex_t *pluginMutex) = 0;
 
-       /* writePatch
-        * Fill a patch with channel values. Returns the index of the last
-        * Patch::channel_t added. */
-
-       virtual int writePatch(int i, bool isProject, class Patch *patch);
-
        /* readPatch
         * Fill channel with data from patch. */
 
@@ -106,16 +100,19 @@ public:
                        pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality);
 
        /* process
-        * merge vChannels into buffer, plus plugin processing (if any). */
+       Merges vChannels into buffer, plus plugin processing (if any). Warning:
+       inBuffer might be nullptr if no input devices are available for recording. */
 
-       virtual void process(float *buffer) = 0;
+       virtual void process(float *outBuffer, float *inBuffer) = 0;
 
        /* start
-        * action to do when channel starts. doQuantize = false (don't
-        * quantize) when Mixer is reading actions from Recorder::. */
+       Action to do when channel starts. doQuantize = false (don't quantize)
+       when Mixer is reading actions from Recorder. If isUserGenerated means that
+       the channel has been started by a human key press and not a pre-recorded
+       action. */
 
        virtual void start(int frame, bool doQuantize, int quantize,
-                       bool mixerIsRunning) = 0;
+                       bool mixerIsRunning, bool forceStart, bool isUserGenerated) = 0;
 
        /* stop
         * action to do when channel is stopped normally (via key or MIDI). */
@@ -167,7 +164,9 @@ public:
         * localFrame  - frame number of the processed buffer
         * globalFrame - actual frame in Mixer */
 
-       virtual void parseAction(recorder::action *a, int localFrame, int globalFrame,
+        // TODO - quantize is useless!
+
+       virtual void parseAction(Recorder::action *a, int localFrame, int globalFrame,
                        int quantize, bool mixerIsRunning) = 0;
 
        /* rewind
@@ -175,25 +174,49 @@ public:
 
        virtual void rewind() = 0;
 
+       /* clear
+       Clears all memory buffers. This is actually useful to sample channels only. */
+
+       virtual void clear() = 0;
+
+       /* canInputRec
+       Tells whether a channel can accept and handle input audio. Always false for
+       Midi channels, true for Sample channels only if they don't contain a
+       sample yet.*/
+
+       virtual bool canInputRec() = 0;
+
+       /* writePatch
+        * Fill a patch with channel values. Returns the index of the last
+        * Patch::channel_t added. */
+
+       virtual int writePatch(int i, bool isProject, class Patch *patch);
+
+       /* receiveMidi
+        * Receives and processes midi messages from external devices. */
+
+       virtual void receiveMidi(uint32_t msg);
+
        /* ------------------------------------------------------------------------ */
 
-       int     index;                // unique id
-       int     type;                 // midi or sample
-       int     status;               // status: see const.h
-       int     key;                  // keyboard button
-       float   volume;               // global volume
-       float   volume_i;             // internal volume
-       float   volume_d;             // delta volume (for envelope)
+       int     index;                 // unique id
+       int     type;                  // midi or sample
+       int     status;                // status: see const.h
+       int     key;                   // keyboard button
+       float   volume;                // global volume
+       float   volume_i;              // internal volume
+       float   volume_d;              // delta volume (for envelope)
        float   panLeft;
        float   panRight;
-       bool    mute_i;               // internal mute
-       bool      mute_s;               // previous mute status after being solo'd
-       bool    mute;                 // global mute
+       bool    mute_i;                // internal mute
+       bool      mute_s;                // previous mute status after being solo'd
+       bool    mute;                  // global mute
        bool    solo;
-  bool    hasActions;           // has something recorded
-       int       recStatus;            // status of recordings (waiting, ending, ...)
-       float  *vChan;                // virtual channel
-  class   gChannel *guiChannel; // pointer to a gChannel object, part of the GUI
+  bool    hasActions;            // has something recorded
+       bool    armed;                                                     // armed for recording
+       int       recStatus;             // status of recordings (waiting, ending, ...)
+       float  *vChan;                 // virtual channel
+  class   geChannel *guiChannel; // pointer to a gChannel object, part of the GUI
 
        // TODO - midi structs, please
 
@@ -201,6 +224,7 @@ public:
   uint32_t midiInKeyPress;
   uint32_t midiInKeyRel;
   uint32_t midiInKill;
+  uint32_t midiInArm;
   uint32_t midiInVolume;
   uint32_t midiInMute;
   uint32_t midiInSolo;
@@ -253,7 +277,9 @@ public:
         * Return a reference to midiBuffer stack. This is available for any kind of
         * channel, but it makes sense only for MIDI channels. */
 
-       juce::MidiBuffer &getPluginMidiEvents() { return midiBuffer; };
+       juce::MidiBuffer &getPluginMidiEvents();
+
+       void clearMidiBuffer();
 
 #endif
 };
index eadbce2e487f1b9bf8afd4ea47cc005e4d078952..021549b99c3f08fa82654b95ee6766eefe89a944 100644 (file)
@@ -30,7 +30,7 @@
 #include <string>
 #include "conf.h"
 #include "const.h"
-#include "../utils/utils.h"
+#include "../utils/fs.h"
 #include "../utils/log.h"
 
 
@@ -44,8 +44,8 @@ Conf::Conf()
 
 #if defined(__linux__) || defined(__APPLE__)
 
-       confFilePath = gGetHomePath() + G_SLASH + CONF_FILENAME;
-       confDirPath  = gGetHomePath() + G_SLASH;
+       confFilePath = gu_getHomePath() + G_SLASH + CONF_FILENAME;
+       confDirPath  = gu_getHomePath() + G_SLASH;
 
 #elif defined(_WIN32)
 
@@ -63,17 +63,17 @@ int Conf::createConfigFolder()
 {
 #if defined(__linux__) || defined(__APPLE__)
 
-       if (gDirExists(confDirPath))
+       if (gu_dirExists(confDirPath))
                return 1;
 
-       gLog("[Conf::createConfigFolder] .giada folder not present. Updating...\n");
+       gu_log("[Conf::createConfigFolder] .giada folder not present. Updating...\n");
 
-       if (gMkdir(confDirPath)) {
-               gLog("[Conf::createConfigFolder] status: ok\n");
+       if (gu_mkdir(confDirPath)) {
+               gu_log("[Conf::createConfigFolder] status: ok\n");
                return 1;
        }
        else {
-               gLog("[Conf::createConfigFolder] status: error!\n");
+               gu_log("[Conf::createConfigFolder] status: error!\n");
                return 0;
        }
 
@@ -178,7 +178,7 @@ int Conf::read()
 
        jRoot = json_load_file(confFilePath.c_str(), 0, &jError);
   if (!jRoot) {
-    gLog("[Conf::read] unable to read configuration file! Error on line %d: %s\n", jError.line, jError.text);
+    gu_log("[Conf::read] unable to read configuration file! Error on line %d: %s\n", jError.line, jError.text);
     return 0;
   }
 
@@ -373,7 +373,7 @@ int Conf::write()
 #endif
 
   if (json_dump_file(jRoot, confFilePath.c_str(), JSON_INDENT(2)) != 0) {
-    gLog("[Conf::write] unable to write configuration file!\n");
+    gu_log("[Conf::write] unable to write configuration file!\n");
     return 0;
   }
   return 1;
index 90b362fb46eb2bfc19c7d487a33fcd54fec75a80..9571b2db9d8e266af6875cbdec80fc98f0d98560 100644 (file)
 
 
 /* -- version --------------------------------------------------------------- */
-#define G_VERSION_STR   "0.13.0"
+#define G_VERSION_STR   "0.13.1"
 #define G_APP_NAME      "Giada"
 #define G_VERSION_MAJOR 0
 #define G_VERSION_MINOR 13
-#define G_VERSION_PATCH 0
+#define G_VERSION_PATCH 1
 
 #define CONF_FILENAME          "giada.conf"
 
@@ -75,6 +75,8 @@
 #define COLOR_TEXT_0   fl_rgb_color(200, 200, 200)
 #define COLOR_TEXT_1   fl_rgb_color(25,  25,  25)      // TODO - duplicate!
 #define COLOR_BG_MAIN  fl_rgb_color(25,  25,  25)                 // windows background
+#define COLOR_BG_RICH  fl_rgb_color(30,  30,  30)                 // lighter background
+#define COLOR_BG_LINE  fl_rgb_color(54,  54,  54)                 // lighter, for bg lines
 #define COLOR_BG_DARK  fl_rgb_color(0,   0,   0)                  // inputs background
 
 
 #define DEFAULT_SAMPLERATE   44100
 #define DEFAULT_BUFSIZE                   1024
 #define DEFAULT_DELAYCOMP               0
-#define DEFAULT_VOL                               0.0f
+#define DEFAULT_VOL                               1.0f
 #define DEFAULT_BOOST                     0.0f
 #define gDEFAULT_PITCH                  1.0f   // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only).
 #define DEFAULT_OUT_VOL           1.0f
-#define DEFAULT_IN_VOL            0.0f
+#define DEFAULT_IN_VOL            1.0f
 #define DEFAULT_CHANMODE          SINGLE_BASIC
 #define DEFAULT_BPM                               120.0f
 #define DEFAULT_BEATS                     4
 #define DEFAULT_QUANTIZE     0           // quantizer off
 #define DEFAULT_FADEOUT_STEP 0.01f  // micro-fadeout speed
 #define DEFAULT_COLUMN_WIDTH 380
+#define G_DEFAULT_PATCH_NAME "(default patch)"
 
 
 
 
 
 /* -- browser types --------------------------------------------------------- */
+/* TODO - USELESS, remove them */
 #define BROWSER_LOAD_PATCH   0x00
 #define BROWSER_LOAD_SAMPLE  0x01
 #define BROWSER_SAVE_PATCH   0x02
 #define MIDI_CONTROLLER     0xB0 << 24
 #define MIDI_NOTE_ON        0x90 << 24
 #define MIDI_NOTE_OFF       0x80 << 24
+#define MIDI_VELOCITY       0x3F <<  8
 #define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16)
 #define MIDI_VOLUME        (MIDI_CONTROLLER) | (0x07 << 16)
 
@@ -350,6 +355,7 @@ const int MIDI_CHANS[16] = {
 #define PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS     "midi_in_keypress"
 #define PATCH_KEY_CHANNEL_MIDI_IN_KEYREL       "midi_in_keyrel"
 #define PATCH_KEY_CHANNEL_MIDI_IN_KILL         "midi_in_kill"
+#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_SOLO         "midi_in_solo"
index 5b4a5eca76a7b39e6b11dc856471506543cbfe99..a7597829ef47424c4db270e52875fd44dad9ac38 100644 (file)
@@ -47,7 +47,7 @@ std::string DataStorageIni::getValue(const char *in)
 
                char buffer[MAX_LINE_LEN];
                if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) {
-                       gLog("[DataStorageIni::getValue] key '%s' not found\n", in);
+                       gu_log("[DataStorageIni::getValue] key '%s' not found\n", in);
                        return "";
                }
 
index 0a485426713706aedcb812945ef7741f5ae7724d..a52f142227d209f5fe46e47ad917a3138f6c3e1d 100644 (file)
@@ -39,7 +39,7 @@ bool DataStorageJson::setString(json_t *jRoot, const char *key, string &output)
 {
   json_t *jObject = json_object_get(jRoot, key);
   if (!json_is_string(jObject)) {
-    gLog("[dataStorageJson::setString] key '%s' is not a string!\n", key);
+    gu_log("[dataStorageJson::setString] key '%s' is not a string!\n", key);
     json_decref(jRoot);
     return false;
   }
@@ -55,12 +55,12 @@ bool DataStorageJson::setFloat(json_t *jRoot, const char *key, float &output)
 {
   json_t *jObject = json_object_get(jRoot, key);
   if (!jObject) {
-    gLog("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key);
+    gu_log("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key);
     output = 0.0f;
     return true;
   }
   if (!json_is_real(jObject)) {
-    gLog("[dataStorageJson::setFloat] key '%s' is not a float!\n", key);
+    gu_log("[dataStorageJson::setFloat] key '%s' is not a float!\n", key);
     json_decref(jRoot);
     return false;
   }
@@ -76,12 +76,12 @@ bool DataStorageJson::setUint32(json_t *jRoot, const char *key, uint32_t &output
 {
   json_t *jObject = json_object_get(jRoot, key);
   if (!jObject) {
-    gLog("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key);
+    gu_log("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key);
     output = 0;
     return true;
   }
   if (!json_is_integer(jObject)) {
-    gLog("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key);
+    gu_log("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key);
     json_decref(jRoot);
     return false;
   }
@@ -97,12 +97,12 @@ bool DataStorageJson::setBool(json_t *jRoot, const char *key, bool &output)
 {
   json_t *jObject = json_object_get(jRoot, key);
   if (!jObject) {
-    gLog("[dataStorageJson::setBool] key '%s' not found, using default value\n", key);
+    gu_log("[dataStorageJson::setBool] key '%s' not found, using default value\n", key);
     output = false;
     return true;
   }
   if (!json_is_boolean(jObject)) {
-    gLog("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key);
+    gu_log("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key);
     json_decref(jRoot);
     return false;
   }
@@ -126,7 +126,7 @@ bool DataStorageJson::setInt(json_t *jRoot, const char *key, int &output)
 bool DataStorageJson::checkObject(json_t *jRoot, const char *key)
 {
   if (!json_is_object(jRoot)) {
-    gLog("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key);
+    gu_log("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key);
     json_decref(jRoot);
     return false;
   }
@@ -140,7 +140,7 @@ bool DataStorageJson::checkObject(json_t *jRoot, const char *key)
 bool DataStorageJson::checkArray(json_t *jRoot, const char *key)
 {
   if (!json_is_array(jRoot)) {
-    gLog("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key);
+    gu_log("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key);
     json_decref(jRoot);
     return false;
   }
index b5b9402469721d4991e11135da1dd67384984dfe..2826793fe903522edf2fb7b552a2fcbd78259e05 100644 (file)
@@ -785,6 +785,48 @@ const char *inputRecOff_xpm[] = {
 "                       ",
 "                       "};
 
+const char *inputToOutputOn_xpm[] = {
+"10 10 8 1",
+"      c #4D4F4C",
+".     c #585A57",
+"+     c #666765",
+"@     c #6F716E",
+"#     c #939592",
+"$     c #999B98",
+"%     c #AEB0AD",
+"&     c #BCBEBB",
+"          ",
+"          ",
+" .#@      ",
+"  #&&#+   ",
+"    @$&%. ",
+"    @$&%. ",
+"  #&&#+   ",
+" .#@      ",
+"          ",
+"          "};
+
+const char *inputToOutputOff_xpm[] = {
+"10 10 8 1",
+"      c #242523",
+".     c #2E302D",
+"+     c #3A3B39",
+"@     c #4F514E",
+"#     c #828481",
+"$     c #8B8D8A",
+"%     c #A7A9A6",
+"&     c #B9BBB7",
+"          ",
+"          ",
+" +$@      ",
+" .#&&#+   ",
+"    @$&%. ",
+"    @$&%. ",
+" .#&&#+   ",
+" +$@      ",
+"          ",
+"          "};
+
 const char *muteOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
@@ -1512,7 +1554,7 @@ const char *fxRemoveOn_xpm[] = {
 #endif // #ifdef WITH_VST
 
 
-const char *beatsDivideOn_xpm[] = {
+const char *divideOn_xpm[] = {
 "18 18 7 1",
 "      c #5A5A5A",
 ".     c #696969",
@@ -1541,7 +1583,7 @@ const char *beatsDivideOn_xpm[] = {
 "                  "};
 
 
-const char *beatsDivideOff_xpm[] = {
+const char *divideOff_xpm[] = {
 "18 18 8 1",
 "      c #252525",
 ".     c #3B3B3B",
@@ -1571,7 +1613,7 @@ const char *beatsDivideOff_xpm[] = {
 "                  "};
 
 
-const char *beatsMultiplyOn_xpm[] = {
+const char *multiplyOn_xpm[] = {
 "18 18 8 1",
 "      c #595B58",
 ".     c #737572",
@@ -1601,7 +1643,7 @@ const char *beatsMultiplyOn_xpm[] = {
 "                  "};
 
 
-const char *beatsMultiplyOff_xpm[] = {
+const char *multiplyOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #4A4C49",
@@ -1690,3 +1732,63 @@ const char *channelPlay_xpm[] = {
 "                  ",
 "                  ",
 "                  "};
+
+
+const char *armOff_xpm[] = {
+"18 18 8 1",
+"      c #242523",
+".     c #4F4445",
+"+     c #514647",
+"@     c #6D5C5E",
+"#     c #8E7372",
+"$     c #AA8889",
+"%     c #AC898A",
+"&     c #B18E8F",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"      +#%%#.      ",
+"     @&&&&&&@     ",
+"    +&&&&&&&&.    ",
+"    #&&&&&&&&#    ",
+"    %&&&&&&&&%    ",
+"    %&&&&&&&&%    ",
+"    #&&&&&&&&#    ",
+"    .&&&&&&&&.    ",
+"     @&&&&&&@     ",
+"      .#%%#.      ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
+
+
+const char *armOn_xpm[] = {
+"18 18 8 1",
+"      c #4D4F4C",
+".     c #6B5077",
+"+     c #805191",
+"@     c #9950AD",
+"#     c #9751B3",
+"$     c #9553AD",
+"%     c #AA52C9",
+"&     c #AE52D1",
+"                  ",
+"                  ",
+"                  ",
+"                  ",
+"      .#%%#.      ",
+"     +&&&&&&+     ",
+"    .&&&&&&&&.    ",
+"    #&&&&&&&&@    ",
+"    %&&&&&&&&%    ",
+"    %&&&&&&&&%    ",
+"    #&&&&&&&&$    ",
+"    .&&&&&&&&.    ",
+"     +&&&&&&+     ",
+"      .@%%$.      ",
+"                  ",
+"                  ",
+"                  ",
+"                  "};
index 39fde4533229e61328918a5d741ca45573b9c857..7d93be8aa72a3f1d838e32c35e940dccf5d83b83 100644 (file)
@@ -68,10 +68,13 @@ extern const char *metronomeOn_xpm[];
 extern const char *inputRecOn_xpm[];
 extern const char *inputRecOff_xpm[];
 
-extern const char *beatsDivideOn_xpm[];
-extern const char *beatsDivideOff_xpm[];
-extern const char *beatsMultiplyOn_xpm[];
-extern const char *beatsMultiplyOff_xpm[];
+extern const char *inputToOutputOn_xpm[];
+extern const char *inputToOutputOff_xpm[];
+
+extern const char *divideOn_xpm[];
+extern const char *divideOff_xpm[];
+extern const char *multiplyOn_xpm[];
+extern const char *multiplyOff_xpm[];
 
 extern const char *muteOff_xpm[];
 extern const char *muteOn_xpm[];
@@ -79,6 +82,9 @@ extern const char *muteOn_xpm[];
 extern const char *soloOff_xpm[];
 extern const char *soloOn_xpm[];
 
+extern const char *armOff_xpm[];
+extern const char *armOn_xpm[];
+
 extern const char *readActionOn_xpm[];
 extern const char *readActionOff_xpm[];
 
index d0771c50173214de240602f980e80fb86631cb77..e280d462de2978645e20b90d0785f3043b63fad5 100644 (file)
@@ -29,8 +29,8 @@
 
 #include <ctime>
 #include "../utils/log.h"
-#include "../utils/utils.h"
-#include "../utils/gui_utils.h"
+#include "../utils/fs.h"
+#include "../utils/gui.h"
 #include "../gui/dialogs/gd_mainWindow.h"
 #include "../gui/dialogs/gd_warnings.h"
 #include "init.h"
 #include "kernelMidi.h"
 
 
+extern KernelAudio   G_KernelAudio;
 extern Mixer                      G_Mixer;
+extern Recorder           G_Recorder;
+extern KernelMidi    G_KernelMidi;
 extern bool                               G_audio_status;
 extern bool                               G_quit;
 extern Patch_DEPR_   G_Patch_DEPR_;
 extern Patch         G_Patch;
 extern Conf          G_Conf;
 extern MidiMapConf   G_MidiMap;
-extern gdMainWindow *mainWin;
+extern gdMainWindow *G_MainWin;
 
 #ifdef WITH_VST
 extern PluginHost G_PluginHost;
@@ -65,24 +68,16 @@ void init_prepareParser()
 {
        time_t t;
   time (&t);
-       gLog("[init] Giada " G_VERSION_STR " - %s", ctime(&t));
+       gu_log("[init] Giada " G_VERSION_STR " - %s", ctime(&t));
 
        G_Conf.read();
        G_Patch_DEPR_.setDefault();
        G_Patch.init();
 
-#ifdef WITH_VST
-
-       G_PluginHost.init(G_Conf.buffersize, G_Conf.samplerate);
-       G_PluginHost.sortPlugins(G_Conf.pluginSortMethod);
-
-#endif
+       if (!gu_logInit(G_Conf.logMode))
+               gu_log("[init] log init failed! Using default stdout\n");
 
-
-       if (!gLog_init(G_Conf.logMode))
-               gLog("[init] log init failed! Using default stdout\n");
-
-       gLog("[init] configuration file ready\n");
+       gu_log("[init] configuration file ready\n");
 }
 
 
@@ -91,16 +86,25 @@ void init_prepareParser()
 
 void init_prepareKernelAudio()
 {
-       kernelAudio::openDevice(
-               G_Conf.soundSystem,
-               G_Conf.soundDeviceOut,
-               G_Conf.soundDeviceIn,
-               G_Conf.channelsOut,
-               G_Conf.channelsIn,
-               G_Conf.samplerate,
-               G_Conf.buffersize);
+       G_KernelAudio.openDevice(G_Conf.soundSystem, G_Conf.soundDeviceOut,
+               G_Conf.soundDeviceIn,   G_Conf.channelsOut, G_Conf.channelsIn,
+               G_Conf.samplerate, G_Conf.buffersize);
        G_Mixer.init();
-       recorder::init();
+       G_Recorder.init();
+
+#ifdef WITH_VST
+
+       /* If with Jack don't use buffer size stored in Conf. Use real buffersize
+       from the soundcard (G_KernelAudio.realBufsize). */
+
+       if (G_Conf.soundSystem == SYS_API_JACK)
+               G_PluginHost.init(G_KernelAudio.realBufsize, G_Conf.samplerate);
+       else
+               G_PluginHost.init(G_Conf.buffersize, G_Conf.samplerate);
+
+       G_PluginHost.sortPlugins(G_Conf.pluginSortMethod);
+
+#endif
 }
 
 
@@ -109,9 +113,9 @@ void init_prepareKernelAudio()
 
 void init_prepareKernelMIDI()
 {
-       kernelMidi::setApi(G_Conf.midiSystem);
-       kernelMidi::openOutDevice(G_Conf.midiPortOut);
-       kernelMidi::openInDevice(G_Conf.midiPortIn);
+       G_KernelMidi.setApi(G_Conf.midiSystem);
+       G_KernelMidi.openOutDevice(G_Conf.midiPortOut);
+       G_KernelMidi.openInDevice(G_Conf.midiPortIn);
 }
 
 
@@ -128,9 +132,9 @@ void init_prepareMidiMap()
        // TODO - do the opposite: if json fails, go with deprecated one
 
        if (G_MidiMap.read(G_Conf.midiMapPath) != MIDIMAP_READ_OK) {
-               gLog("[init_prepareMidiMap] JSON-based midimap read failed, trying with the deprecated one...\n");
+               gu_log("[init_prepareMidiMap] JSON-based midimap read failed, trying with the deprecated one...\n");
                if (G_MidiMap.readMap_DEPR_(G_Conf.midiMapPath) == MIDIMAP_INVALID)
-                       gLog("[init_prepareMidiMap] unable to read deprecated midimap. Nothing to do\n");
+                       gu_log("[init_prepareMidiMap] unable to read deprecated midimap. Nothing to do\n");
                }
 }
 
@@ -140,25 +144,20 @@ void init_prepareMidiMap()
 
 void init_startGUI(int argc, char **argv)
 {
-       char win_label[32];
-       sprintf(win_label, "%s - %s",
-                                       G_APP_NAME,
-                                       !strcmp(G_Patch_DEPR_.name, "") ? "(default patch)" : G_Patch_DEPR_.name);
+       G_MainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, "", argc, argv);
+       G_MainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW,
+    G_Conf.mainWindowH);
 
-       mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv);
-       mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH);
+  gu_updateMainWinLabel(G_Patch.name == "" ? G_DEFAULT_PATCH_NAME : G_Patch.name);
 
        /* never update the GUI elements if G_audio_status is bad, segfaults
         * are around the corner */
 
        if (G_audio_status)
                gu_updateControls();
-
-       if (!G_audio_status)
-               gdAlert(
-                       "Your soundcard isn't configured correctly.\n"
-                       "Check the configuration and restart Giada."
-               );
+  else
+               gdAlert("Your soundcard isn't configured correctly.\n"
+                       "Check the configuration and restart Giada.");
 }
 
 /* -------------------------------------------------------------------------- */
@@ -167,7 +166,7 @@ void init_startGUI(int argc, char **argv)
 void init_startKernelAudio()
 {
        if (G_audio_status)
-               kernelAudio::startStream();
+               G_KernelAudio.startStream();
 }
 
 
@@ -180,41 +179,41 @@ void init_shutdown()
 
        /* store position and size of the main window for the next startup */
 
-       G_Conf.mainWindowX = mainWin->x();
-       G_Conf.mainWindowY = mainWin->y();
-       G_Conf.mainWindowW = mainWin->w();
-       G_Conf.mainWindowH = mainWin->h();
+       G_Conf.mainWindowX = G_MainWin->x();
+       G_Conf.mainWindowY = G_MainWin->y();
+       G_Conf.mainWindowW = G_MainWin->w();
+       G_Conf.mainWindowH = G_MainWin->h();
 
        /* close any open subwindow, especially before cleaning PluginHost_DEPR_ to
         * avoid mess */
 
        gu_closeAllSubwindows();
-       gLog("[init] all subwindows closed\n");
+       gu_log("[init] all subwindows closed\n");
 
        /* write configuration file */
 
        if (!G_Conf.write())
-               gLog("[init] error while saving configuration file!\n");
+               gu_log("[init] error while saving configuration file!\n");
        else
-               gLog("[init] configuration saved\n");
+               gu_log("[init] configuration saved\n");
 
        /* if G_audio_status we close the kernelAudio FIRST, THEN the mixer.
         * The opposite could cause random segfaults (even now with RtAudio?). */
 
        if (G_audio_status) {
-               kernelAudio::closeDevice();
+               G_KernelAudio.closeDevice();
                G_Mixer.close();
-               gLog("[init] Mixer closed\n");
+               gu_log("[init] Mixer closed\n");
        }
 
-       recorder::clearAll();
-       gLog("[init] Recorder cleaned up\n");
+       G_Recorder.clearAll();
+       gu_log("[init] Recorder cleaned up\n");
 
 #ifdef WITH_VST
        G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins);
-       gLog("[init] PluginHost cleaned up\n");
+       gu_log("[init] PluginHost cleaned up\n");
 #endif
 
-       gLog("[init] Giada " G_VERSION_STR " closed\n\n");
-       gLog_close();
+       gu_log("[init] Giada " G_VERSION_STR " closed\n\n");
+       gu_logClose();
 }
index d9dbb0eb5d337c2eeeb4c7d0b58667e5a5be4112..b487df9fc582c8001573c5d87ab4dc639c291f76 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <vector>
-#include <cstring>
 #include "../utils/log.h"
-#include "../glue/glue.h"
-#include "kernelAudio.h"
+#include "../glue/main.h"
+#include "conf.h"
 #include "mixer.h"
+#include "const.h"
+#include "kernelAudio.h"
 
-#include "conf.h"
+
+extern KernelAudio G_KernelAudio;
+extern Mixer       G_Mixer;
+extern Conf        G_Conf;
+extern bool           G_audio_status;
 
 
-extern Mixer G_Mixer;
-extern Conf  G_Conf;
-extern bool     G_audio_status;
+using std::string;
+using std::vector;
 
 
-namespace kernelAudio
+KernelAudio::KernelAudio()
 {
-RtAudio  *system       = NULL;
-unsigned  numDevs      = 0;
-bool             inputEnabled = 0;
-unsigned  realBufsize  = 0;
-int       api          = 0;
-
-int openDevice(
-       int _api,
-       int outDev,
-       int inDev,
-       int outChan,
-       int inChan,
-       int samplerate,
-       int buffersize)
+       system       = nullptr;
+       numDevs      = 0;
+       inputEnabled = 0;
+       realBufsize  = 0;
+       api          = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+
+int KernelAudio::openDevice(int _api, int outDev,      int inDev, int outChan,
+       int inChan, int samplerate, int buffersize)
 {
        api = _api;
-       gLog("[KA] using system 0x%x\n", api);
+       gu_log("[KA] using system 0x%x\n", api);
 
 #if defined(__linux__)
 
@@ -88,7 +91,7 @@ int openDevice(
 
        if (api == SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE))
                system = new RtAudio(RtAudio::MACOSX_CORE);
-               
+
 #endif
 
        else {
@@ -96,27 +99,22 @@ int openDevice(
                return 0;
        }
 
-
-
-       //gLog("[KA] %d\n", sizeof(system->rtapi_));
-
-       gLog("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate);
+       gu_log("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate);
 
        numDevs = system->getDeviceCount();
 
        if (numDevs < 1) {
-               gLog("[KA] no devices found with this API\n");
+               gu_log("[KA] no devices found with this API\n");
                closeDevice();
                G_audio_status = false;
                return 0;
        }
        else {
-               gLog("[KA] %d device(s) found\n", numDevs);
+               gu_log("[KA] %d device(s) found\n", numDevs);
                for (unsigned i=0; i<numDevs; i++)
-                       gLog("  %d) %s\n", i, getDeviceName(i).c_str());
+                       gu_log("  %d) %s\n", i, getDeviceName(i).c_str());
        }
 
-
        RtAudio::StreamParameters outParams;
        RtAudio::StreamParameters inParams;
 
@@ -124,6 +122,7 @@ int openDevice(
                outParams.deviceId = getDefaultOut();
        else
                outParams.deviceId = outDev;
+
        outParams.nChannels = 2;
        outParams.firstChannel = outChan*2; // chan 0=0, 1=2, 2=4, ...
 
@@ -138,7 +137,6 @@ int openDevice(
        else
                inputEnabled = false;
 
-
   RtAudio::StreamOptions options;
   options.streamName = "Giada";
   options.numberOfBuffers = 4;
@@ -148,20 +146,20 @@ int openDevice(
 #if defined(__linux__) || defined(__APPLE__)
        if (api == SYS_API_JACK) {
                samplerate = getFreq(outDev, 0);
-               gLog("[KA] JACK in use, freq = %d\n", samplerate);
+               gu_log("[KA] JACK in use, freq = %d\n", samplerate);
                G_Conf.samplerate = samplerate;
        }
 #endif
 
        try {
                system->openStream(
-                       &outParams,                                               // output params
-                       inDev != -1 ? &inParams : NULL, // input params if inDevice is selected
-                       RTAUDIO_FLOAT32,                                  // audio format
-                       samplerate,                                               // sample rate
-                       &realBufsize,                                     // buffer size in byte
-                       &G_Mixer.masterPlay,            // audio callback
-                       NULL,                                                                             // user data (unused)
+                       &outParams,                                                   // output params
+                       inDev != -1 ? &inParams : nullptr,  // input params if inDevice is selected
+                       RTAUDIO_FLOAT32,                                      // audio format
+                       samplerate,                                                   // sample rate
+                       &realBufsize,                                         // buffer size in byte
+                       &G_Mixer.masterPlay,                // audio callback
+                       nullptr,                                                                                  // user data (unused)
                        &options);
                G_audio_status = true;
 
@@ -173,7 +171,7 @@ int openDevice(
                return 1;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] system init error: %s\n", e.getMessage().c_str());
+               gu_log("[KA] system init error: %s\n", e.getMessage().c_str());
                closeDevice();
                G_audio_status = false;
                return 0;
@@ -184,15 +182,15 @@ int openDevice(
 /* -------------------------------------------------------------------------- */
 
 
-int startStream()
+int KernelAudio::startStream()
 {
        try {
                system->startStream();
-               gLog("[KA] latency = %lu\n", system->getStreamLatency());
+               gu_log("[KA] latency = %lu\n", system->getStreamLatency());
                return 1;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] Start stream error: %s\n", e.getMessage().c_str());
+               gu_log("[KA] Start stream error: %s\n", e.getMessage().c_str());
                return 0;
        }
 }
@@ -201,14 +199,14 @@ int startStream()
 /* -------------------------------------------------------------------------- */
 
 
-int stopStream()
+int KernelAudio::stopStream()
 {
        try {
                system->stopStream();
                return 1;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] Stop stream error\n");
+               gu_log("[KA] Stop stream error\n");
                return 0;
        }
 }
@@ -217,13 +215,13 @@ int stopStream()
 /* -------------------------------------------------------------------------- */
 
 
-string getDeviceName(unsigned dev)
+string KernelAudio::getDeviceName(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).name;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] invalid device ID = %d\n", dev);
+               gu_log("[KA] invalid device ID = %d\n", dev);
                return "";
        }
 }
@@ -232,7 +230,7 @@ string getDeviceName(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-int closeDevice()
+int KernelAudio::closeDevice()
 {
        if (system->isStreamOpen()) {
 #if defined(__linux__) || defined(__APPLE__)
@@ -242,7 +240,7 @@ int closeDevice()
 #endif
                system->closeStream();
                delete system;
-               system = NULL;
+               system = nullptr;
        }
        return 1;
 }
@@ -251,7 +249,7 @@ int closeDevice()
 /* -------------------------------------------------------------------------- */
 
 
-unsigned getMaxInChans(int dev)
+unsigned KernelAudio::getMaxInChans(int dev)
 {
        if (dev == -1) return 0;
 
@@ -259,7 +257,7 @@ unsigned getMaxInChans(int dev)
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).inputChannels;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] Unable to get input channels\n");
+               gu_log("[KA] Unable to get input channels\n");
                return 0;
        }
 }
@@ -268,13 +266,13 @@ unsigned getMaxInChans(int dev)
 /* -------------------------------------------------------------------------- */
 
 
-unsigned getMaxOutChans(unsigned dev)
+unsigned KernelAudio::getMaxOutChans(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).outputChannels;
        }
        catch (RtAudioError &e) {
-               gLog("[KA] Unable to get output channels\n");
+               gu_log("[KA] Unable to get output channels\n");
                return 0;
        }
 }
@@ -283,7 +281,7 @@ unsigned getMaxOutChans(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-bool isProbed(unsigned dev)
+bool KernelAudio::isProbed(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).probed;
@@ -297,7 +295,7 @@ bool isProbed(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-unsigned getDuplexChans(unsigned dev)
+unsigned KernelAudio::getDuplexChans(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).duplexChannels;
@@ -311,7 +309,7 @@ unsigned getDuplexChans(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-bool isDefaultIn(unsigned dev)
+bool KernelAudio::isDefaultIn(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultInput;
@@ -325,7 +323,7 @@ bool isDefaultIn(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-bool isDefaultOut(unsigned dev)
+bool KernelAudio::isDefaultOut(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultOutput;
@@ -339,7 +337,7 @@ bool isDefaultOut(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-int getTotalFreqs(unsigned dev)
+int KernelAudio::getTotalFreqs(unsigned dev)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.size();
@@ -353,7 +351,7 @@ int getTotalFreqs(unsigned dev)
 /* -------------------------------------------------------------------------- */
 
 
-int    getFreq(unsigned dev, int i)
+int    KernelAudio::getFreq(unsigned dev, int i)
 {
        try {
                return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.at(i);
@@ -367,12 +365,12 @@ int       getFreq(unsigned dev, int i)
 /* -------------------------------------------------------------------------- */
 
 
-int getDefaultIn()
+int KernelAudio::getDefaultIn()
 {
        return system->getDefaultInputDevice();
 }
 
-int getDefaultOut()
+int KernelAudio::getDefaultOut()
 {
        return system->getDefaultOutputDevice();
 }
@@ -381,7 +379,7 @@ int getDefaultOut()
 /* -------------------------------------------------------------------------- */
 
 
-int    getDeviceByName(const char *name)
+int    KernelAudio::getDeviceByName(const char *name)
 {
        for (unsigned i=0; i<numDevs; i++)
                if (name == getDeviceName(i))
@@ -393,9 +391,9 @@ int getDeviceByName(const char *name)
 /* -------------------------------------------------------------------------- */
 
 
-bool hasAPI(int API)
+bool KernelAudio::hasAPI(int API)
 {
-       std::vector<RtAudio::Api> APIs;
+       vector<RtAudio::Api> APIs;
        RtAudio::getCompiledApi(APIs);
        for (unsigned i=0; i<APIs.size(); i++)
                if (APIs.at(i) == API)
@@ -407,7 +405,7 @@ bool hasAPI(int API)
 /* -------------------------------------------------------------------------- */
 
 
-std::string getRtAudioVersion()
+string KernelAudio::getRtAudioVersion()
 {
        return RtAudio::getVersion();
 }
@@ -417,16 +415,27 @@ std::string getRtAudioVersion()
 
 
 #ifdef __linux__
-#include <jack/jack.h>
-#include <jack/intclient.h>
-#include <jack/transport.h>
 
-jack_client_t *jackGetHandle()
+int KernelAudio::jackSyncCb(jack_transport_state_t state, jack_position_t *pos,
+       void *arg)
+{
+       return G_KernelAudio.__jackSyncCb(state, pos, arg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+jack_client_t *KernelAudio::jackGetHandle()
 {
        return (jack_client_t*) system->rtapi_->__HACK__getJackClient();
 }
 
-void jackStart()
+
+/* -------------------------------------------------------------------------- */
+
+
+void KernelAudio::jackStart()
 {
        if (api == SYS_API_JACK) {
                jack_client_t *client = jackGetHandle();
@@ -435,7 +444,10 @@ void jackStart()
 }
 
 
-void jackStop()
+/* -------------------------------------------------------------------------- */
+
+
+void KernelAudio::jackStop()
 {
        if (api == SYS_API_JACK) {
                jack_client_t *client = jackGetHandle();
@@ -444,42 +456,46 @@ void jackStop()
 }
 
 
-void jackSetSyncCb()
+/* -------------------------------------------------------------------------- */
+
+
+void KernelAudio::jackSetSyncCb()
 {
        jack_client_t *client = jackGetHandle();
-       jack_set_sync_callback(client, jackSyncCb, NULL);
+       jack_set_sync_callback(client, jackSyncCb, nullptr);
        //jack_set_sync_timeout(client, 8);
 }
 
 
-int jackSyncCb(jack_transport_state_t state, jack_position_t *pos,
+/* -------------------------------------------------------------------------- */
+
+
+int KernelAudio::__jackSyncCb(jack_transport_state_t state, jack_position_t *pos,
                void *arg)
 {
        switch (state) {
                case JackTransportStopped:
-                       gLog("[KA] Jack transport stopped, frame=%d\n", pos->frame);
+                       gu_log("[KA] Jack transport stopped, frame=%d\n", pos->frame);
                        glue_stopSeq(false);  // false = not from GUI
                        if (pos->frame == 0)
                                glue_rewindSeq();
                        break;
 
                case JackTransportRolling:
-                       gLog("[KA] Jack transport rolling\n");
+                       gu_log("[KA] Jack transport rolling\n");
                        break;
 
                case JackTransportStarting:
-                       gLog("[KA] Jack transport starting, frame=%d\n", pos->frame);
+                       gu_log("[KA] Jack transport starting, frame=%d\n", pos->frame);
                        glue_startSeq(false);  // false = not from GUI
                        if (pos->frame == 0)
                                glue_rewindSeq();
                        break;
 
                default:
-                       gLog("[KA] Jack transport [unknown]\n");
+                       gu_log("[KA] Jack transport [unknown]\n");
        }
        return 1;
 }
 
 #endif
-
-}
index 2ab1e12db8176acc34764f58c373434595f013c8..ba3667ef3b7066951a3b495c65947f41df319d5a 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * KernelAudio
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef KERNELAUDIO_H
 
 
 #include "../deps/rtaudio-mod/RtAudio.h"
-#if defined(__linux__)
+#ifdef __linux__
        #include <jack/jack.h>
        #include <jack/intclient.h>
        #include <jack/transport.h>
 #endif
 
 
-using std::string;
+class KernelAudio
+{
+public:
 
+       KernelAudio();
 
-namespace kernelAudio {
+       int openDevice(int api, int outDev,     int inDev, int outChan, int inChan,
+               int samplerate, int buffersize);
 
-       int openDevice(
-                       int api,
-                       int outDev,
-                       int inDev,
-                       int outChan,
-                       int inChan,
-                       int samplerate,
-                       int buffersize);
        int closeDevice();
 
        int startStream();
@@ -60,7 +56,7 @@ namespace kernelAudio {
        bool                      isProbed         (unsigned dev);
        bool                isDefaultIn      (unsigned dev);
        bool                      isDefaultOut     (unsigned dev);
-       string      getDeviceName    (unsigned dev);
+       std::string getDeviceName    (unsigned dev);
        unsigned    getMaxInChans    (int dev);
        unsigned    getMaxOutChans   (unsigned dev);
        unsigned    getDuplexChans   (unsigned dev);
@@ -70,29 +66,27 @@ namespace kernelAudio {
        int         getDefaultOut    ();
        int         getDefaultIn     ();
        bool        hasAPI           (int API);
-       string      getRtAudioVersion();
+       std::string getRtAudioVersion();
 
 #ifdef __linux__
+
        jack_client_t *jackGetHandle();
        void jackStart();
        void jackStop();
        void jackSetSyncCb();
-       int  jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg);
+       static int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg);
+       int __jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg);
+       
 #endif
 
-       /* *** how to avoid multiple definition of ***
-        * When you declare a variable in a header file, every source file that
-        * includes that header, either directly or indirectly, gets its own
-        * separate copy of the variable. Then when you go to link all the .o
-        * files together, the linker sees that the variable is instantiated
-        * in a bunch of .o files. Make it extern in the header file and
-        * instantiate it in memory.cpp. */
-
-       extern RtAudio  *system;
-       extern unsigned  numDevs;
-       extern bool              inputEnabled;
-       extern unsigned  realBufsize;           // reale bufsize from the soundcard
-       extern int       api;
-}
+       unsigned numDevs;
+       bool             inputEnabled;
+       unsigned realBufsize;           // reale bufsize from the soundcard
+       int      api;
+
+private:
+
+       RtAudio *system;
+};
 
 #endif
index 36c99d979c73b429e071292945318442307a9e56..9676143aff5411d91e4a613baf6bb2fa5a3589db 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <stdio.h>
+#include <RtMidi.h>
 #include "../utils/log.h"
-#include "../glue/glue.h"
-#include "kernelMidi.h"
+#include "../glue/channel.h"
+#include "../glue/main.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"
+#include "pluginHost.h"
+#include "kernelMidi.h"
 
 
 extern bool        G_midiStatus;
 extern Conf        G_Conf;
 extern Mixer       G_Mixer;
+extern KernelMidi  G_KernelMidi;
 extern MidiMapConf G_MidiMap;
+extern PluginHost  G_PluginHost;
 
 
 using std::string;
+using std::vector;
+
+
+KernelMidi::KernelMidi()
+       :       numOutPorts(0),
+               numInPorts (0),
+               api        (0),      // one api for both in & out
+               midiOut    (nullptr),
+               midiIn     (nullptr),
+               cb_learn   (nullptr),
+               cb_data    (nullptr)
+{
+}
 
 
-namespace kernelMidi
+/* -------------------------------------------------------------------------- */
+
+
+void KernelMidi::callback(double t, vector<unsigned char> *msg, void *data)
 {
-int        api         = 0;      // one api for both in & out
-RtMidiOut *midiOut     = NULL;
-RtMidiIn  *midiIn      = NULL;
-unsigned   numOutPorts = 0;
-unsigned   numInPorts  = 0;
+       G_KernelMidi.__callback(t, msg, data);
+}
+
 
-cb_midiLearn *cb_learn = NULL;
-void         *cb_data  = NULL;
+/* -------------------------------------------------------------------------- */
 
 
-void __sendMidiLightningInitMsgs__()
+void KernelMidi::sendMidiLightningInitMsgs()
 {
        for(unsigned i=0; i<G_MidiMap.initCommands.size(); i++) {
                MidiMapConf::message_t msg = G_MidiMap.initCommands.at(i);
                if (msg.value != 0x0 && msg.channel != -1) {
-                       gLog("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", msg.channel, msg.value);
+                       gu_log("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", msg.channel, msg.value);
                        send(msg.value | MIDI_CHANS[msg.channel]);
                }
        }
@@ -74,7 +94,7 @@ void __sendMidiLightningInitMsgs__()
 /* -------------------------------------------------------------------------- */
 
 
-void startMidiLearn(cb_midiLearn *cb, void *data)
+void KernelMidi::startMidiLearn(cb_midiLearn *cb, void *data)
 {
        cb_learn = cb;
        cb_data  = data;
@@ -84,34 +104,34 @@ void startMidiLearn(cb_midiLearn *cb, void *data)
 /* -------------------------------------------------------------------------- */
 
 
-void stopMidiLearn()
+void KernelMidi::stopMidiLearn()
 {
-       cb_learn = NULL;
-       cb_data  = NULL;
+       cb_learn = nullptr;
+       cb_data  = nullptr;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void setApi(int _api)
+void KernelMidi::setApi(int _api)
 {
        api = _api;
-       gLog("[KM] using system 0x%x\n", api);
+       gu_log("[KM] using system 0x%x\n", api);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int openOutDevice(int port)
+int KernelMidi::openOutDevice(int port)
 {
        try {
                midiOut = new RtMidiOut((RtMidi::Api) api, "Giada MIDI Output");
                G_midiStatus = true;
   }
   catch (RtMidiError &error) {
-    gLog("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
+    gu_log("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
     G_midiStatus = false;
     return 0;
   }
@@ -119,25 +139,25 @@ int openOutDevice(int port)
        /* print output ports */
 
        numOutPorts = midiOut->getPortCount();
-  gLog("[KM] %d output MIDI ports found\n", numOutPorts);
+  gu_log("[KM] %d output MIDI ports found\n", numOutPorts);
   for (unsigned i=0; i<numOutPorts; i++)
-               gLog("  %d) %s\n", i, getOutPortName(i).c_str());
+               gu_log("  %d) %s\n", i, getOutPortName(i).c_str());
 
        /* try to open a port, if enabled */
 
        if (port != -1 && numOutPorts > 0) {
                try {
                        midiOut->openPort(port, getOutPortName(port));
-                       gLog("[KM] MIDI out port %d open\n", port);
+                       gu_log("[KM] MIDI out port %d open\n", port);
 
                        /* TODO - it shold send midiLightning message only if there is a map loaded
                        and available in G_MidiMap. */
 
-                       __sendMidiLightningInitMsgs__();
+                       sendMidiLightningInitMsgs();
                        return 1;
                }
                catch (RtMidiError &error) {
-                       gLog("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str());
+                       gu_log("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str());
                        G_midiStatus = false;
                        return 0;
                }
@@ -150,14 +170,14 @@ int openOutDevice(int port)
 /* -------------------------------------------------------------------------- */
 
 
-int openInDevice(int port)
+int KernelMidi::openInDevice(int port)
 {
        try {
                midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input");
                G_midiStatus = true;
   }
   catch (RtMidiError &error) {
-    gLog("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
+    gu_log("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
     G_midiStatus = false;
     return 0;
   }
@@ -165,9 +185,9 @@ int openInDevice(int port)
        /* print input ports */
 
        numInPorts = midiIn->getPortCount();
-  gLog("[KM] %d input MIDI ports found\n", numInPorts);
+  gu_log("[KM] %d input MIDI ports found\n", numInPorts);
   for (unsigned i=0; i<numInPorts; i++)
-               gLog("  %d) %s\n", i, getInPortName(i).c_str());
+               gu_log("  %d) %s\n", i, getInPortName(i).c_str());
 
        /* try to open a port, if enabled */
 
@@ -175,12 +195,12 @@ int openInDevice(int port)
                try {
                        midiIn->openPort(port, getInPortName(port));
                        midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
-                       gLog("[KM] MIDI in port %d open\n", port);
+                       gu_log("[KM] MIDI in port %d open\n", port);
                        midiIn->setCallback(&callback);
                        return 1;
                }
                catch (RtMidiError &error) {
-                       gLog("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str());
+                       gu_log("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str());
                        G_midiStatus = false;
                        return 0;
                }
@@ -193,9 +213,9 @@ int openInDevice(int port)
 /* -------------------------------------------------------------------------- */
 
 
-bool hasAPI(int API)
+bool KernelMidi::hasAPI(int API)
 {
-       std::vector<RtMidi::Api> APIs;
+       vector<RtMidi::Api> APIs;
        RtMidi::getCompiledApi(APIs);
        for (unsigned i=0; i<APIs.size(); i++)
                if (APIs.at(i) == API)
@@ -207,13 +227,13 @@ bool hasAPI(int API)
 /* -------------------------------------------------------------------------- */
 
 
-string getOutPortName(unsigned p)
+string KernelMidi::getOutPortName(unsigned p)
 {
        try { return midiOut->getPortName(p); }
        catch (RtMidiError &error) { return ""; }
 }
 
-string getInPortName(unsigned p)
+string KernelMidi::getInPortName(unsigned p)
 {
        try { return midiIn->getPortName(p); }
        catch (RtMidiError &error) { return ""; }
@@ -223,29 +243,29 @@ string getInPortName(unsigned p)
 /* -------------------------------------------------------------------------- */
 
 
-void send(uint32_t data)
+void KernelMidi::send(uint32_t data)
 {
        if (!G_midiStatus)
                return;
 
-  std::vector<unsigned char> msg(1, getB1(data));
+  vector<unsigned char> msg(1, getB1(data));
   msg.push_back(getB2(data));
   msg.push_back(getB3(data));
 
        midiOut->sendMessage(&msg);
-       gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
+       gu_log("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void send(int b1, int b2, int b3)
+void KernelMidi::send(int b1, int b2, int b3)
 {
        if (!G_midiStatus)
                return;
 
-       std::vector<unsigned char> msg(1, b1);
+       vector<unsigned char> msg(1, b1);
 
        if (b2 != -1)
                msg.push_back(b2);
@@ -253,23 +273,23 @@ void send(int b1, int b2, int b3)
                msg.push_back(b3);
 
        midiOut->sendMessage(&msg);
-       //gLog("[KM] send msg=(%X %X %X)\n", b1, b2, b3);
+       //gu_log("[KM] send msg=(%X %X %X)\n", b1, b2, b3);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void callback(double t, std::vector<unsigned char> *msg, void *data)
+void KernelMidi::__callback(double t, vector<unsigned char> *msg, void *data)
 {
        /* 0.8.0 - for now we handle other midi signals (common and real-time
         * messages) as unknown, for debugging purposes */
 
        if (msg->size() < 3) {
-               gLog("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
+               gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
                for (unsigned i=0; i<msg->size(); i++)
-                       gLog("%X", (int) msg->at(i));
-               gLog("\n");
+                       gu_log("%X", (int) msg->at(i));
+               gu_log("\n");
                return;
        }
 
@@ -282,104 +302,122 @@ void callback(double t, std::vector<unsigned char> *msg, void *data)
        uint32_t value = input & 0x0000FF00;
        uint32_t pure  = 0x00;
        if (!G_Conf.noNoteOff)
-               pure  = input & 0xFFFF0000;   // input without 'value' byte
+               pure = input & 0xFFFF0000;   // input without 'value' byte
        else
-               pure  = input & 0xFFFFFF00;   // input with 'value' byte
+               pure = input & 0xFFFFFF00;   // input with 'value' byte
 
-       gLog("[KM] MIDI received - 0x%X (chan %d)", input, chan >> 24);
+       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)   {
-               gLog("\n");
+       if (cb_learn)
                cb_learn(pure, cb_data);
-       }
        else {
+               processMaster(pure, value);
+               processChannels(pure, value);
+       }
+}
 
-               /* process master events */
 
-               if      (pure == G_Conf.midiInRewind) {
-                       gLog(" >>> rewind (global) (pure=0x%X)", pure);
-                       glue_rewindSeq();
-               }
-               else if (pure == G_Conf.midiInStartStop) {
-                       gLog(" >>> startStop (global) (pure=0x%X)", pure);
-                       glue_startStopSeq();
-               }
-               else if (pure == G_Conf.midiInActionRec) {
-                       gLog(" >>> actionRec (global) (pure=0x%X)", pure);
-                       glue_startStopActionRec();
+/* -------------------------------------------------------------------------- */
+
+
+void KernelMidi::processMaster(uint32_t pure, uint32_t value)
+{
+       if      (pure == G_Conf.midiInRewind) {
+               gu_log("  >>> rewind (master) (pure=0x%X)\n", pure);
+               glue_rewindSeq();
+       }
+       else if (pure == G_Conf.midiInStartStop) {
+               gu_log("  >>> startStop (master) (pure=0x%X)\n", pure);
+               glue_startStopSeq(false);
+       }
+       else if (pure == G_Conf.midiInActionRec) {
+               gu_log("  >>> actionRec (master) (pure=0x%X)\n", pure);
+               glue_startStopActionRec(false);
+       }
+       else if (pure == G_Conf.midiInInputRec) {
+               gu_log("  >>> inputRec (master) (pure=0x%X)\n", pure);
+               glue_startStopInputRec(false);
+       }
+       else if (pure == G_Conf.midiInMetronome) {
+               gu_log("  >>> metronome (master) (pure=0x%X)\n", pure);
+               glue_startStopMetronome(false);
+       }
+       else if (pure == G_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 == G_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 == G_Conf.midiInBeatDouble) {
+               gu_log("  >>> sequencer x2 (master) (pure=0x%X)\n", pure);
+               glue_beatsMultiply();
+       }
+       else if (pure == G_Conf.midiInBeatHalf) {
+               gu_log("  >>> sequencer /2 (master) (pure=0x%X)\n", pure);
+               glue_beatsDivide();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void KernelMidi::processChannels(uint32_t pure, uint32_t value)
+{
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+
+               Channel *ch = (Channel*) G_Mixer.channels.at(i);
+
+               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 == G_Conf.midiInInputRec) {
-                       gLog(" >>> inputRec (global) (pure=0x%X)", pure);
-                       glue_startStopInputRec(false, false);   // update gui, no popup messages
+               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 == G_Conf.midiInMetronome) {
-                       gLog(" >>> metronome (global) (pure=0x%X)", pure);
-                       glue_startStopMetronome(false);
+               else if (pure == ch->midiInMute) {
+                       gu_log("  >>> mute ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_setMute(ch, false);
                }
-               else if (pure == G_Conf.midiInVolumeIn) {
-                       float vf = (value >> 8)/127.0f;
-                       gLog(" >>> input volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
-                       glue_setInVol(vf, false);
+               else if (pure == ch->midiInSolo) {
+                       gu_log("  >>> solo ch=%d (pure=0x%X)\n", ch->index, pure);
+                       ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false);
                }
-               else if (pure == G_Conf.midiInVolumeOut) {
+               else if (pure == ch->midiInVolume) {
                        float vf = (value >> 8)/127.0f;
-                       gLog(" >>> output volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf);
-                       glue_setOutVol(vf, false);
+                       gu_log("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n",
+                               ch->index, pure, value >> 8, vf);
+                       glue_setChanVol(ch, vf, false);
                }
-               else if (pure == G_Conf.midiInBeatDouble) {
-                       gLog(" >>> sequencer x2 (global) (pure=0x%X)", pure);
-                       glue_beatsMultiply();
+               else if (pure == ((SampleChannel*)ch)->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",
+                               ch->index, pure, value >> 8, vf);
+                       glue_setPitch(nullptr, (SampleChannel*)ch, vf, false);
                }
-               else if (pure == G_Conf.midiInBeatHalf) {
-                       gLog(" >>> sequencer /2 (global) (pure=0x%X)", pure);
-                       glue_beatsDivide();
+               else if (pure == ((SampleChannel*)ch)->midiInReadActions) {
+                       gu_log("  >>> start/stop read actions ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_startStopReadingRecs((SampleChannel*)ch, false);
                }
 
-               /* process channels */
-
-               for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-
-                       Channel *ch = (Channel*) G_Mixer.channels.at(i);
-
-                       if (!ch->midiIn) continue;
-
-                       if      (pure == ch->midiInKeyPress) {
-                               gLog(" >>> keyPress, ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_keyPress(ch, false, false);
-                       }
-                       else if (pure == ch->midiInKeyRel) {
-                               gLog(" >>> keyRel ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_keyRelease(ch, false, false);
-                       }
-                       else if (pure == ch->midiInMute) {
-                               gLog(" >>> mute ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_setMute(ch, false);
-                       }
-                       else if (pure == ch->midiInSolo) {
-                               gLog(" >>> solo ch=%d (pure=0x%X)", ch->index, pure);
-                               ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false);
-                       }
-                       else if (pure == ch->midiInVolume) {
-                               float vf = (value >> 8)/127.0f;
-                               gLog(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
-                               glue_setChanVol(ch, vf, false);
-                       }
-                       else if (pure == ((SampleChannel*)ch)->midiInPitch) {
-                               float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0]
-                               gLog(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf);
-                               glue_setPitch(NULL, (SampleChannel*)ch, vf, false);
-                       }
-                       else if (pure == ((SampleChannel*)ch)->midiInReadActions) {
-                               gLog(" >>> start/stop read actions ch=%d (pure=0x%X)", ch->index, pure);
-                               glue_startStopReadingRecs((SampleChannel*)ch, false);
-                       }
-               }
-               gLog("\n");
+               /* redirect full midi message to plugins */
+
+               ch->receiveMidi(pure | value);
        }
 }
 
@@ -387,13 +425,7 @@ void callback(double t, std::vector<unsigned char> *msg, void *data)
 /* -------------------------------------------------------------------------- */
 
 
-std::string getRtMidiVersion()
+string KernelMidi::getRtMidiVersion()
 {
        return midiOut->getVersion();
 }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-}  // namespace
index 161a95380ea6876b2f75f69e4e4416e7ac52948c..834e0de43ccdb20c0eade05db176a8deaaa6be15 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * KernelMidi
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef KERNELMIDI_H
 #define KERNELMIDI_H
 
 
-#include <stdint.h>
-#include <RtMidi.h>
-#include "channel.h"
-
+#ifdef __APPLE__  // our compiler still doesn't know about cstdint (c++11 stuff)
+       #include <stdint.h>
+#else
+       #include <cstdint>
+#endif
+#include <string>
+#include <vector>
 
-using std::string;
 
+class KernelMidi
+{
+public:
 
-namespace kernelMidi {
+       unsigned numOutPorts;
+       unsigned numInPorts;
 
-       extern int      api;      // one api for both in & out
-       extern unsigned numOutPorts;
-       extern unsigned numInPorts;
+       KernelMidi();
 
        typedef void (cb_midiLearn) (uint32_t, void *);
 
-       /* cb_learn
-        * callback prepared by the gdMidiGrabber window and called by
-        * kernelMidi. It contains things to do once the midi message has been
-        * stored. */
-
-       extern cb_midiLearn *cb_learn;
-       extern void         *cb_data;
-
        void startMidiLearn(cb_midiLearn *cb, void *data);
        void stopMidiLearn();
 
-       inline int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; }
-       inline int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; }
-       inline int getB3(uint32_t iValue) { return (iValue >> 8)  & 0xFF; }
+       int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; }
+       int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; }
+       int getB3(uint32_t iValue) { return (iValue >> 8)  & 0xFF; }
 
-       inline uint32_t getIValue(int b1, int b2, int b3) {
+       uint32_t getIValue(int b1, int b2, int b3) {
                return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00);
        }
 
@@ -91,17 +87,38 @@ namespace kernelMidi {
        /* getIn/OutPortName
         * return the name of the port 'p'. */
 
-       string getInPortName(unsigned p);
-       string getOutPortName(unsigned p);
+       std::string getInPortName(unsigned p);
+       std::string getOutPortName(unsigned p);
 
        bool hasAPI(int API);
 
+       std::string getRtMidiVersion();
+
+private:
+
+       int      api;
+       class RtMidiOut *midiOut;
+       class RtMidiIn  *midiIn;
+
+       /* 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;
+       void         *cb_data;
+
        /* callback
         * master callback for input events. */
 
-       void callback(double t, std::vector<unsigned char> *msg, void *data);
+       static void callback(double t, std::vector<unsigned char> *msg, void *data);
+       void __callback(double t, std::vector<unsigned char> *msg, void *data);
+
+       void sendMidiLightningInitMsgs();
+
 
-       string getRtMidiVersion();
-}
+       void processMaster(uint32_t pure, uint32_t value);
+       void processChannels(uint32_t pure, uint32_t value);
+};
 
 #endif
index 3dd0cefdaa512d435a9eb44ef3647913613d614a..cf1f88ac76c51f265d2e83376ff443684e2812a6 100644 (file)
 #include "patch_DEPR_.h"
 #include "patch.h"
 #include "conf.h"
+#include "mixer.h"
 #include "kernelMidi.h"
 
 
+extern Recorder   G_Recorder;
+extern KernelMidi G_KernelMidi;
+extern PluginHost G_PluginHost;
+extern Mixer      G_Mixer;
+
+
 MidiChannel::MidiChannel(int bufferSize, MidiMapConf *midiMapConf)
        : Channel    (CHANNEL_MIDI, STATUS_OFF, bufferSize, midiMapConf),
          midiOut    (false),
          midiOutChan(MIDI_CHANS[0])
 {
-#ifdef WITH_VST // init VstEvents stack
-       freeVstMidiEvents(true);
-#endif
 }
 
 
@@ -69,28 +73,14 @@ void MidiChannel::copy(const Channel *_src, pthread_mutex_t *pluginMutex)
 /* -------------------------------------------------------------------------- */
 
 
-#ifdef WITH_VST
-
-void MidiChannel::freeVstMidiEvents(bool init)
-{
-       midiBuffer.clear();
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
 #ifdef WITH_VST
 
 void MidiChannel::addVstMidiEvent(uint32_t msg, int localFrame)
 {
        juce::MidiMessage message = juce::MidiMessage(
-               kernelMidi::getB1(msg),
-               kernelMidi::getB2(msg),
-               kernelMidi::getB3(msg));
-
+               G_KernelMidi.getB1(msg),
+               G_KernelMidi.getB2(msg),
+               G_KernelMidi.getB3(msg));
        midiBuffer.addEvent(message, localFrame);
 }
 
@@ -124,7 +114,7 @@ void MidiChannel::quantize(int index, int localFrame, int globalFrame) {}
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::parseAction(recorder::action *a, int localFrame,
+void MidiChannel::parseAction(Recorder::action *a, int localFrame,
                int globalFrame, int quantize, bool mixerIsRunning)
 {
        if (a->type == ACTION_MIDI)
@@ -156,7 +146,7 @@ void MidiChannel::setMute(bool internal)
 {
        mute = true;    // internal mute does not exist for midi (for now)
        if (midiOut)
-               kernelMidi::send(MIDI_ALL_NOTES_OFF);
+               G_KernelMidi.send(MIDI_ALL_NOTES_OFF);
 #ifdef WITH_VST
                addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0);
 #endif
@@ -177,16 +167,16 @@ void MidiChannel::unsetMute(bool internal)
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::process(float *buffer)
+void MidiChannel::process(float *outBuffer, float *inBuffer)
 {
 #ifdef WITH_VST
        pluginHost->processStack(vChan, PluginHost::CHANNEL, this);
-       freeVstMidiEvents();
 #endif
 
+       /* TODO - isn't this useful only if WITH_VST ? */
        for (int j=0; j<bufferSize; j+=2) {
-               buffer[j]   += vChan[j]   * volume; // * panLeft;   future?
-               buffer[j+1] += vChan[j+1] * volume; // * panRight;  future?
+               outBuffer[j]   += vChan[j]   * volume; // * panLeft;   future?
+               outBuffer[j+1] += vChan[j+1] * volume; // * panRight;  future?
        }
 }
 
@@ -195,7 +185,7 @@ void MidiChannel::process(float *buffer)
 
 
 void MidiChannel::start(int frame, bool doQuantize, int quantize,
-               bool mixerIsRunning)
+               bool mixerIsRunning, bool forceStart, bool isUserGenerated)
 {
        switch (status) {
                case STATUS_PLAY:
@@ -231,7 +221,7 @@ void MidiChannel::kill(int frame)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING)) {
                if (midiOut)
-                       kernelMidi::send(MIDI_ALL_NOTES_OFF);
+                       G_KernelMidi.send(MIDI_ALL_NOTES_OFF);
 #ifdef WITH_VST
                addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0);
 #endif
@@ -285,11 +275,11 @@ int MidiChannel::readPatch(const string &basePath, int i, Patch *patch,
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::sendMidi(recorder::action *a, int localFrame)
+void MidiChannel::sendMidi(Recorder::action *a, int localFrame)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
                if (midiOut)
-                       kernelMidi::send(a->iValue | MIDI_CHANS[midiOutChan]);
+                       G_KernelMidi.send(a->iValue | MIDI_CHANS[midiOutChan]);
 
 #ifdef WITH_VST
                addVstMidiEvent(a->iValue, localFrame);
@@ -302,7 +292,7 @@ void MidiChannel::sendMidi(uint32_t data)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
                if (midiOut)
-                       kernelMidi::send(data | MIDI_CHANS[midiOutChan]);
+                       G_KernelMidi.send(data | MIDI_CHANS[midiOutChan]);
 #ifdef WITH_VST
                addVstMidiEvent(data, 0);
 #endif
@@ -316,7 +306,7 @@ void MidiChannel::sendMidi(uint32_t data)
 void MidiChannel::rewind()
 {
        if (midiOut)
-               kernelMidi::send(MIDI_ALL_NOTES_OFF);
+               G_KernelMidi.send(MIDI_ALL_NOTES_OFF);
 #ifdef WITH_VST
                addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0);
 #endif
@@ -336,3 +326,41 @@ int MidiChannel::writePatch(int i, bool isProject, Patch *patch)
 
        return 0;
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::receiveMidi(uint32_t msg)
+{
+  if (!armed)
+    return;
+  while (true) {
+    if (pthread_mutex_trylock(&G_PluginHost.mutex_midi) != 0)
+      continue;
+    gu_log("[Channel::processMidi] msg=%X\n", msg);
+#ifdef WITH_VST
+    addVstMidiEvent(msg, 0);
+#endif
+    pthread_mutex_unlock(&G_PluginHost.mutex_midi);
+    break;
+  }
+
+       if (G_Recorder.canRec(this))
+               G_Recorder.rec(index, ACTION_MIDI, G_Mixer.actualFrame, msg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool MidiChannel::canInputRec()
+{
+       return false; // midi channels don't handle input audio
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::clear() {}
index 011ae2f550693cdb911a3dda3153f01629a3e9a8..dcaaa27e8d98265c910aa35727af1ee0295d75e2 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * channel
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef MIDI_CHANNEL_H
@@ -48,43 +48,41 @@ public:
   bool    midiOut;           // enable midi output
   uint8_t midiOutChan;       // midi output channel
 
-       void copy(const Channel *src, pthread_mutex_t *pluginMutex);
-
-       void process    (float *buffer);
-       void start      (int frame, bool doQuantize, int quantize, bool mixerIsRunning);
-       void kill       (int frame);
-       void empty      ();
-       void stopBySeq  (bool chansStopOnSeqHalt);
-       void stop       ();
-       void rewind     ();
-       void setMute    (bool internal);
-       void unsetMute  (bool internal);
-       int  readPatch_DEPR_  (const char *file, int i, class Patch_DEPR_ *patch,
-                       int samplerate, int rsmpQuality);
-       int  readPatch  (const string &basePath, int i, class Patch *patch,
-                       pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality);
-       int  writePatch (int i, bool isProject, class Patch *patch);
-       void quantize   (int index, int localFrame, int globalFrame);
-       void onZero     (int frame, bool recsStopOnChanHalt);
-       void onBar      (int frame);
-       void parseAction(recorder::action *a, int localFrame, int globalFrame,
-                       int quantize, bool mixerIsRunning);
-
-       /* ---------------------------------------------------------------- */
+       void copy(const Channel *src, pthread_mutex_t *pluginMutex) override;
+       void clear() override;
+       void process(float *outBuffer, float *inBuffer) override;
+       void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning,
+                 bool forceStart, bool isUserGenerated) override;
+       void kill(int frame) override;
+       void empty() override;
+       void stopBySeq(bool chansStopOnSeqHalt) override;
+       void stop() override;
+       void rewind() override;
+       void setMute(bool internal) override;
+       void unsetMute(bool internal) override;
+       int readPatch_DEPR_(const char *file, int i, class Patch_DEPR_ *patch,
+                       int samplerate, int rsmpQuality) override;
+       int readPatch(const string &basePath, int i, class Patch *patch,
+                       pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override;
+       int writePatch(int i, bool isProject, class Patch *patch) override;
+       void quantize(int index, int localFrame, int globalFrame) override;
+       void onZero(int frame, bool recsStopOnChanHalt) override;
+       void onBar(int frame) override;
+       void parseAction(Recorder::action *a, int localFrame, int globalFrame,
+                       int quantize, bool mixerIsRunning) override;
+       void receiveMidi(uint32_t msg) override;
+       bool canInputRec() override;
+
+       /* ------------------------------------------------------------------------ */
 
        /* sendMidi
         * send Midi event to the outside world. */
 
-       void sendMidi(recorder::action *a, int localFrame);
+       void sendMidi(Recorder::action *a, int localFrame);
        void sendMidi(uint32_t data);
 
-#ifdef WITH_VST
-
-       /* freeVstMidiEvents
-        * empty vstEvents structure. Init: use the method for channel
-        * initialization. */
 
-       void freeVstMidiEvents(bool init=false);
+#ifdef WITH_VST
 
        /* addVstMidiEvent
         * Add a new Midi event to the midiEvent stack fom a composite uint32_t raw
index 41d37060337cf8748d90fc7253677a8c50250ffb..c2b40eb301cf5fd0d4cd2b6629e35d5254f62f9b 100644 (file)
@@ -35,7 +35,7 @@
 #include <dirent.h>
 #include "midiMapConf.h"
 #include "const.h"
-#include "../utils/utils.h"
+#include "../utils/string.h"
 #include "../utils/log.h"
 
 
@@ -46,18 +46,18 @@ using std::vector;
 
 void MidiMapConf::init()
 {
-       midimapsPath = gGetHomePath() + G_SLASH + "midimaps" + G_SLASH;
+       midimapsPath = gu_getHomePath() + G_SLASH + "midimaps" + G_SLASH;
 
        /* scan dir of midi maps and load the filenames into <>maps. */
 
-       gLog("[MidiMapConf::init] scanning midimaps directory...\n");
+       gu_log("[MidiMapConf::init] scanning midimaps directory...\n");
 
   DIR    *dp;
   dirent *ep;
   dp = opendir(midimapsPath.c_str());
 
        if (!dp) {
-               gLog("[MidiMapConf::init] unable to scan midimaps directory!\n");
+               gu_log("[MidiMapConf::init] unable to scan midimaps directory!\n");
                return;
        }
 
@@ -67,12 +67,12 @@ void MidiMapConf::init()
 
                // TODO - check if is a valid midimap file (verify headers)
 
-               gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name);
+               gu_log("[MidiMapConf::init] found midimap '%s'\n", ep->d_name);
 
                maps.push_back(ep->d_name);
        }
 
-       gLog("[MidiMapConf::init] total midimaps found: %d\n", maps.size());
+       gu_log("[MidiMapConf::init] total midimaps found: %d\n", maps.size());
        closedir(dp);
 }
 
@@ -125,16 +125,16 @@ void MidiMapConf::setDefault()
 int MidiMapConf::read(const string &file)
 {
        if (file.empty()) {
-               gLog("[MidiMapConf::read] midimap not specified, nothing to do\n");
+               gu_log("[MidiMapConf::read] midimap not specified, nothing to do\n");
                return MIDIMAP_NOT_SPECIFIED;
        }
 
-       gLog("[MidiMapConf::read] reading midimap file '%s'\n", file.c_str());
+       gu_log("[MidiMapConf::read] reading midimap file '%s'\n", file.c_str());
 
        string path = midimapsPath + file;
        jRoot = json_load_file(path.c_str(), 0, &jError);
        if (!jRoot) {
-    gLog("[MidiMapConf::read] unreadable midimap file. Error on line %d: %s\n", jError.line, jError.text);
+    gu_log("[MidiMapConf::read] unreadable midimap file. Error on line %d: %s\n", jError.line, jError.text);
     return MIDIMAP_UNREADABLE;
   }
 
@@ -178,7 +178,7 @@ bool MidiMapConf::readInitCommands(json_t *jContainer)
        json_t *jInitCommand;
        json_array_foreach(jInitCommands, commandIndex, jInitCommand) {
 
-               string indexStr = "init command " + gItoa(commandIndex);
+               string indexStr = "init command " + gu_itoa(commandIndex);
                if (!checkObject(jInitCommand, indexStr.c_str()))
                        return 0;
 
@@ -238,7 +238,7 @@ void MidiMapConf::parse(message_t *message)
 
        message->value = strtoul(output.c_str(), NULL, 16);
 
-       gLog("[MidiMapConf::parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n",
+       gu_log("[MidiMapConf::parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n",
                        message->channel, message->valueStr.c_str(), message->value, message->offset);
 }
 
@@ -296,16 +296,16 @@ void MidiMapConf::setDefault_DEPR_()
 int MidiMapConf::readMap_DEPR_(string file)
 {
        if (file.empty()) {
-               gLog("[MidiMapConf::readMap_DEPR_] midimap not specified, nothing to do\n");
+               gu_log("[MidiMapConf::readMap_DEPR_] midimap not specified, nothing to do\n");
                return MIDIMAP_NOT_SPECIFIED;
        }
 
-       gLog("[MidiMapConf::readMap_DEPR_] reading midimap file '%s'\n", file.c_str());
+       gu_log("[MidiMapConf::readMap_DEPR_] reading midimap file '%s'\n", file.c_str());
 
        string path = midimapsPath + file;
        fp = fopen(path.c_str(), "r");
        if (!fp) {
-               gLog("[MidiMapConf::readMap_DEPR_] unreadable midimap file\n");
+               gu_log("[MidiMapConf::readMap_DEPR_] unreadable midimap file\n");
                return MIDIMAP_UNREADABLE;
        }
 
@@ -313,20 +313,20 @@ int MidiMapConf::readMap_DEPR_(string file)
        device = getValue("device");
 
        if (brand.empty() || device.empty()) {
-               gLog("[MidiMapConf::readMap_DEPR_] invalid midimap file\n");
+               gu_log("[MidiMapConf::readMap_DEPR_] invalid midimap file\n");
                return MIDIMAP_INVALID;
        }
 
-       gLog("[MidiMapConf::readMap_DEPR_] reading midimap for %s %s\n",
+       gu_log("[MidiMapConf::readMap_DEPR_] reading midimap for %s %s\n",
                        brand.c_str(), device.c_str());
 
        /* parse init commands */
 
        vector<string> ic;
-       gSplit(getValue("init_commands"), ";", &ic);
+       gu_split(getValue("init_commands"), ";", &ic);
        for (unsigned i=0; i<(unsigned)MAX_INIT_COMMANDS && i<ic.size(); i++) {
                sscanf(ic.at(i).c_str(), "%d:%x", &init_channels[i], &init_messages[i]);
-               gLog("[MidiMapConf::readMap_DEPR_] init command %d - channel %d - message 0x%X\n",
+               gu_log("[MidiMapConf::readMap_DEPR_] init command %d - channel %d - message 0x%X\n",
                                i, init_channels[i], init_messages[i]);
 
                /* forward compatibility */
@@ -396,7 +396,7 @@ void MidiMapConf::close_DEPR_()
 
 void MidiMapConf::parse_DEPR_(string key, int *chan, uint32_t *msg, int *offset)
 {
-       gLog("[MidiMapConf::parse_DEPR_] command %s - ", key.c_str());
+       gu_log("[MidiMapConf::parse_DEPR_] command %s - ", key.c_str());
        string value = getValue(key.c_str());
 
        /* grab channel part, i.e. [channel]:*/
@@ -428,5 +428,5 @@ void MidiMapConf::parse_DEPR_(string key, int *chan, uint32_t *msg, int *offset)
 
        *msg = strtoul(strmsg, NULL, 16);  // from string to uint32_t
 
-       gLog("chan=%d value=%s msg=%#x, offset=%d\n", *chan, midiParts.c_str(), *msg, *offset);
+       gu_log("chan=%d value=%s msg=%#x, offset=%d\n", *chan, midiParts.c_str(), *msg, *offset);
 }
index fd07358fdf729063655856044695c490279156cc..f7e76df2e2e05a4e14fef39c86b2c0266dd53729 100644 (file)
@@ -36,7 +36,7 @@
 #include <vector>
 #include "dataStorageIni.h"
 #include "dataStorageJson.h"
-#include "../utils/utils.h"
+#include "../utils/fs.h"
 #if defined(__APPLE__)
 #include <pwd.h>
 #endif
index 5ca38cdf7cf881b13421792767451a3a17a1675f..7321f1b97609025138514fa7eaff6e19b45c9ef5 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <math.h>
 #include "../utils/log.h"
-#include "../utils/gui_utils.h"
-#include "mixer.h"
-#include "init.h"
 #include "wave.h"
 #include "recorder.h"
 #include "pluginHost.h"
 #include "sampleChannel.h"
 #include "midiChannel.h"
 #include "kernelMidi.h"
+#include "mixer.h"
 
 
+extern KernelAudio G_KernelAudio;
 extern Mixer                    G_Mixer;
+extern Recorder    G_Recorder;
+extern KernelMidi  G_KernelMidi;
 extern MidiMapConf G_MidiMap;
 extern Patch_DEPR_ G_Patch_DEPR_;
 extern Conf                             G_Conf;
@@ -62,12 +62,6 @@ Mixer::Mixer()
 /* -------------------------------------------------------------------------- */
 
 
-Mixer::~Mixer() {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 #define TICKSIZE 38
 
 
@@ -102,6 +96,7 @@ void Mixer::init()
        docross     = false;
        rewindWait  = false;
        running     = false;
+       recording   = false;
        ready       = true;
        waitRec     = 0;
        actualFrame = 0;
@@ -120,7 +115,6 @@ void Mixer::init()
        inVol        = DEFAULT_IN_VOL;
        peakOut      = 0.0f;
        peakIn       = 0.0f;
-       chanInput    = NULL;
        inputTracker = 0;
 
        actualBeat    = 0;
@@ -137,7 +131,7 @@ void Mixer::init()
        /** TODO - set kernelAudio::realBufsize * 2 as private member */
 
        vChanInput   = NULL;
-       vChanInToOut = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
+       vChanInToOut = (float *) malloc(G_KernelAudio.realBufsize * 2 * sizeof(float));
 
        pthread_mutex_init(&mutex_recs, NULL);
        pthread_mutex_init(&mutex_chans, NULL);
@@ -154,7 +148,7 @@ void Mixer::init()
 Channel *Mixer::addChannel(int type)
 {
        Channel *ch;
-       int bufferSize = kernelAudio::realBufsize*2;
+       int bufferSize = G_KernelAudio.realBufsize * 2;
 
        if (type == CHANNEL_SAMPLE)
                ch = new SampleChannel(bufferSize, &G_MidiMap);
@@ -175,7 +169,7 @@ Channel *Mixer::addChannel(int type)
        }
 
        ch->index = getNewIndex();
-       gLog("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size());
+       gu_log("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size());
        return ch;
 }
 
@@ -214,7 +208,7 @@ int Mixer::deleteChannel(Channel *ch)
        }
 
        if (index == -1) {
-               gLog("[Mixer::deleteChannel] unable to find Channel %d for deletion!\n", ch->index);
+               gu_log("[Mixer::deleteChannel] unable to find Channel %d for deletion!\n", ch->index);
                return 0;
        }
 
@@ -228,7 +222,7 @@ int Mixer::deleteChannel(Channel *ch)
                        return 1;
                }
                //else
-               //      gLog("[mixer::deleteChannel] waiting for mutex...\n");
+               //      gu_log("[mixer::deleteChannel] waiting for mutex...\n");
        }
 }
 
@@ -241,7 +235,7 @@ Channel *Mixer::getChannelByIndex(int index)
        for (unsigned i=0; i<channels.size(); i++)
                if (channels.at(i)->index == index)
                        return channels.at(i);
-       gLog("[mixer::getChannelByIndex] channel at index %d not found!\n", index);
+       gu_log("[mixer::getChannelByIndex] channel at index %d not found!\n", index);
        return NULL;
 }
 
@@ -253,7 +247,7 @@ void Mixer::sendMIDIsync()
 {
        if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
                if (actualFrame % (framesPerBeat/24) == 0)
-                       kernelMidi::send(MIDI_CLOCK, -1, -1);
+                       G_KernelMidi.send(MIDI_CLOCK, -1, -1);
        }
        else
        if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
@@ -271,10 +265,10 @@ void Mixer::sendMIDIsync()
                         * seconds high nibble */
 
                        if (midiTCframes % 2 == 0) {
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F)  | 0x00, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4)    | 0x10, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4)   | 0x30, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F)  | 0x00, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCframes >> 4)    | 0x10, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCseconds >> 4)   | 0x30, -1);
                        }
 
                        /* minutes low nibble
@@ -283,10 +277,10 @@ void Mixer::sendMIDIsync()
                         * hours high nibble SMPTE frame rate */
 
                        else {
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4)   | 0x50, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F)   | 0x60, -1);
-                               kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4)     | 0x70, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCminutes >> 4)   | 0x50, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTChours & 0x0F)   | 0x60, -1);
+                               G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTChours >> 4)     | 0x70, -1);
                        }
 
                        midiTCframes++;
@@ -305,7 +299,7 @@ void Mixer::sendMIDIsync()
                                                midiTCminutes = 0;
                                        }
                                }
-                               //gLog("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes);
+                               //gu_log("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes);
                        }
                }
        }
@@ -328,250 +322,64 @@ void Mixer::sendMIDIrewind()
         * SMPTE time in one message */
 
        if (G_Conf.midiSync == MIDI_SYNC_MTC_M) {
-               kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00);  // send msg on channel 0
-               kernelMidi::send(0x01, 0x01, 0x00);        // hours 0
-               kernelMidi::send(0x00, 0x00, 0x00);        // mins, secs, frames 0
-               kernelMidi::send(MIDI_EOX, -1, -1);        // end of sysex
+               G_KernelMidi.send(MIDI_SYSEX, 0x7F, 0x00);  // send msg on channel 0
+               G_KernelMidi.send(0x01, 0x01, 0x00);        // hours 0
+               G_KernelMidi.send(0x00, 0x00, 0x00);        // mins, secs, frames 0
+               G_KernelMidi.send(MIDI_EOX, -1, -1);        // end of sysex
        }
 }
 
 /* -------------------------------------------------------------------------- */
 
 
-int Mixer::masterPlay(
-       void *out_buf, void *in_buf, unsigned n_frames,
+int Mixer::masterPlay(void *outBuf, void *inBuf, unsigned bufferSize,
        double streamTime, RtAudioStreamStatus status, void *userData)
 {
-       return G_Mixer.__masterPlay(out_buf, in_buf, n_frames);
+       return G_Mixer.__masterPlay(outBuf, inBuf, bufferSize);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames)
+int Mixer::__masterPlay(void *_outBuf, void *_inBuf, unsigned bufferSize)
 {
        if (!ready)
                return 0;
 
-       float *outBuf = ((float *) out_buf);
-       float *inBuf  = ((float *) in_buf);
-       bufferFrames *= 2;     // stereo
+       float *outBuf = (float *) _outBuf;
+       float *inBuf  = G_KernelAudio.inputEnabled ? (float *) _inBuf : nullptr;
+       bufferSize   *= 2;     // stereo
        peakOut       = 0.0f;  // reset peak calculator
        peakIn        = 0.0f;  // reset peak calculator
 
-       /* always clean each buffer */
-
-       memset(outBuf, 0, sizeof(float) * bufferFrames);         // out
-       memset(vChanInToOut, 0, sizeof(float) * bufferFrames);   // inToOut vChan
-
-       pthread_mutex_lock(&mutex_chans);
-       for (unsigned i=0; i<channels.size(); i++)
-               if (channels.at(i)->type == CHANNEL_SAMPLE)
-                       ((SampleChannel*)channels.at(i))->clear();
-       pthread_mutex_unlock(&mutex_chans);
-
-       for (unsigned j=0; j<bufferFrames; j+=2) {
-
-               if (kernelAudio::inputEnabled) {
-
-                       /* input peak calculation (left chan only so far). */
-
-                       if (inBuf[j] * inVol > peakIn)
-                               peakIn = inBuf[j] * inVol;
-
-                       /* "hear what you're playing" - process, copy and paste the input buffer
-                        * onto the output buffer */
-
-                       if (inToOut) {
-                               vChanInToOut[j]   = inBuf[j]   * inVol;
-                               vChanInToOut[j+1] = inBuf[j+1] * inVol;
-                       }
-               }
-
-               /* operations to do if the sequencer is running:
-                * - compute quantizer
-                * - time check for LOOP_REPEAT
-                * - reset loops at beat 0
-                * - read recorded actions
-                * - reset actualFrame */
+       clearAllBuffers(outBuf, bufferSize);
 
+       for (unsigned j=0; j<bufferSize; j+=2) {
+               processLineIn(inBuf, j);
                if (running) {
-
-                       /* line in recording */
-
-                       if (chanInput != NULL && kernelAudio::inputEnabled) {
-
-                               /* delay comp: wait until waitRec reaches delayComp. WaitRec
-                                * returns to 0 in mixerHandler, as soon as the recording ends */
-
-                               if (waitRec < G_Conf.delayComp)
-                                       waitRec += 2;
-                               else {
-                                       vChanInput[inputTracker]   += inBuf[j]   * inVol;
-                                       vChanInput[inputTracker+1] += inBuf[j+1] * inVol;
-                                       inputTracker += 2;
-                                       if (inputTracker >= totalFrames)
-                                               inputTracker = 0;
-                               }
-                       }
-
-                       /* quantizer computations: quantize rewind and all channels. */
-
-                       if (quantize > 0 && quanto > 0) {
-                               if (actualFrame % (quanto) == 0) {   // is quanto!
-                                       if (rewindWait) {
-                                               rewindWait = false;
-                                               rewind();
-                                       }
-                                       pthread_mutex_lock(&mutex_chans);
-                                       for (unsigned k=0; k<channels.size(); k++)
-                                               channels.at(k)->quantize(k, j, actualFrame);  // j == localFrame
-                                       pthread_mutex_unlock(&mutex_chans);
-                               }
-                       }
-
-                       /* reset LOOP_REPEAT, if a bar has passed */
-
-                       if (actualFrame % framesPerBar == 0 && actualFrame != 0) {
-                               if (metronome)
-                                       tickPlay = true;
-
-                               pthread_mutex_lock(&mutex_chans);
-                               for (unsigned k=0; k<channels.size(); k++)
-                                       channels.at(k)->onBar(j);
-                               pthread_mutex_unlock(&mutex_chans);
-                       }
-
-                       /* reset loops on beat 0 */
-
-                       if (actualFrame == 0) {
-                               pthread_mutex_lock(&mutex_chans);
-                               for (unsigned k=0; k<channels.size(); k++)
-                                       channels.at(k)->onZero(j, G_Conf.recsStopOnChanHalt);
-                               pthread_mutex_unlock(&mutex_chans);
-                       }
-
-                       /* reading all actions recorded */
-
-                       pthread_mutex_lock(&mutex_recs);
-                       for (unsigned y=0; y<recorder::frames.size(); y++) {
-                               if (recorder::frames.at(y) == actualFrame) {
-                                       for (unsigned z=0; z<recorder::global.at(y).size(); z++) {
-                                               int index   = recorder::global.at(y).at(z)->chan;
-                                               Channel *ch = getChannelByIndex(index);
-                                               ch->parseAction(recorder::global.at(y).at(z), j, actualFrame, quantize, running);
-                                       }
-                                       break;
-                               }
-                       }
-                       pthread_mutex_unlock(&mutex_recs);
-
-                       /* increase actualFrame */
-
+                       lineInRec(inBuf, j);
+                       doQuantize(j);
+                       testBar(j);
+                       testFirstBeat(j);
+                       readActions(j);
                        actualFrame += 2;
-
-                       /* if actualFrame > totalFrames the sequencer returns to frame 0,
-                        * beat 0. This must be the last operation. */
-
-                       if (actualFrame > totalFrames) {
-                               actualFrame = 0;
-                               actualBeat  = 0;
-                       }
-                       else
-                       if (actualFrame % framesPerBeat == 0 && actualFrame > 0) {
-                               actualBeat++;
-
-                               /* avoid tick and tock to overlap when a new bar has passed (which
-                                * is also a beat) */
-
-                               if (metronome && !tickPlay)
-                                       tockPlay = true;
-                       }
-
+                       testLastBeat();  // this test must be the last one
                        sendMIDIsync();
-
-               } // if (running)
-
-               /* sum channels, CHANNEL_SAMPLE only */
-
-               pthread_mutex_lock(&mutex_chans);
-               for (unsigned k=0; k<channels.size(); k++) {
-                       if (channels.at(k)->type == CHANNEL_SAMPLE)
-                               ((SampleChannel*)channels.at(k))->sum(j, running);
                }
-               pthread_mutex_unlock(&mutex_chans);
-
-               /* metronome play */
-               /** FIXME - move this one after the peak meter calculation */
-
-               if (tockPlay) {
-                       outBuf[j]   += tock[tockTracker];
-                       outBuf[j+1] += tock[tockTracker];
-                       tockTracker++;
-                       if (tockTracker >= TICKSIZE-1) {
-                               tockPlay    = false;
-                               tockTracker = 0;
-                       }
-               }
-               if (tickPlay) {
-                       outBuf[j]   += tick[tickTracker];
-                       outBuf[j+1] += tick[tickTracker];
-                       tickTracker++;
-                       if (tickTracker >= TICKSIZE-1) {
-                               tickPlay    = false;
-                               tickTracker = 0;
-                       }
-               }
-       } // end loop J
-
-
-       /* final loop: sum virtual channels and process plugins. */
-
-       pthread_mutex_lock(&mutex_chans);
-       for (unsigned k=0; k<channels.size(); k++)
-               channels.at(k)->process(outBuf);
-       pthread_mutex_unlock(&mutex_chans);
-
-       /* processing fxs master in & out, if any. */
-
-#ifdef WITH_VST
-       pthread_mutex_lock(&mutex_plugins);
-       G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT);
-       G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN);
-       pthread_mutex_unlock(&mutex_plugins);
-#endif
-
-       /* post processing master fx + peak calculation. */
-
-       for (unsigned j=0; j<bufferFrames; j+=2) {
-
-               /* merging vChanInToOut, if enabled */
-
-               if (inToOut) {
-                       outBuf[j]   += vChanInToOut[j];
-                       outBuf[j+1] += vChanInToOut[j+1];
-               }
-
-               outBuf[j]   *= outVol;
-               outBuf[j+1] *= outVol;
-
-               /* computes the peak for the left channel (so far). */
+               sumChannels(j);
+       }
 
-               if (outBuf[j] > peakOut)
-                       peakOut = outBuf[j];
+       renderIO(outBuf, inBuf);
 
-               if (G_Conf.limitOutput) {
-                       if (outBuf[j] > 1.0f)
-                               outBuf[j] = 1.0f;
-                       else if (outBuf[j] < -1.0f)
-                               outBuf[j] = -1.0f;
+       /* post processing */
 
-                       if (outBuf[j+1] > 1.0f)
-                               outBuf[j+1] = 1.0f;
-                       else if (outBuf[j+1] < -1.0f)
-                               outBuf[j+1] = -1.0f;
-               }
+       for (unsigned j=0; j<bufferSize; j+=2) {
+               finalizeOutput(outBuf, j);
+               if (G_Conf.limitOutput)
+                       limitOutput(outBuf, j);
+               computePeak(outBuf, j);
+               renderMetronome(outBuf, j);
        }
 
        return 0;
@@ -613,7 +421,7 @@ void Mixer::updateFrameBars()
                free(vChanInput);
        vChanInput = (float*) malloc(totalFrames * sizeof(float));
        if (!vChanInput)
-               gLog("[Mixer] vChanInput realloc error!\n");
+               gu_log("[Mixer] vChanInput realloc error!\n");
 }
 
 
@@ -711,19 +519,279 @@ bool Mixer::hasEditedSamples()
 /* -------------------------------------------------------------------------- */
 
 
-bool Mixer::mergeVirtualInput()
+void Mixer::mergeVirtualInput()
 {
-       if (vChanInput == NULL) {
-               gLog("[Mixer] virtual input channel not alloc'd\n");
-               return false;
+       for (unsigned i=0; i<channels.size(); i++) {
+               if (channels.at(i)->type == CHANNEL_MIDI)
+                       continue;
+               SampleChannel *ch = (SampleChannel*) channels.at(i);
+               if (ch->armed)
+                       memcpy(ch->wave->data, vChanInput, totalFrames * sizeof(float));
+       }
+       memset(vChanInput, 0, totalFrames * sizeof(float)); // clear vchan
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::lineInRec(float *inBuf, unsigned frame)
+{
+       if (!mh_hasArmedSampleChannels() || !G_KernelAudio.inputEnabled || !recording)
+               return;
+
+       /* Delay comp: wait until waitRec reaches delayComp. WaitRec
+        * returns to 0 in mixerHandler, as soon as the recording ends */
+
+       if (waitRec < G_Conf.delayComp) {
+               waitRec += 2;
+               return;
+       }
+
+       vChanInput[inputTracker]   += inBuf[frame]   * inVol;
+       vChanInput[inputTracker+1] += inBuf[frame+1] * inVol;
+       inputTracker += 2;
+       if (inputTracker >= totalFrames)
+               inputTracker = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::processLineIn(float *inBuf, unsigned frame)
+{
+       if (!G_KernelAudio.inputEnabled)
+               return;
+
+       /* input peak calculation (left chan only so far). */
+
+       if (inBuf[frame] * inVol > peakIn)
+               peakIn = inBuf[frame] * inVol;
+
+       /* "hear what you're playing" - process, copy and paste the input buffer
+        * onto the output buffer */
+
+       if (inToOut) {
+               vChanInToOut[frame]   = inBuf[frame]   * inVol;
+               vChanInToOut[frame+1] = inBuf[frame+1] * inVol;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::readActions(unsigned frame)
+{
+       pthread_mutex_lock(&mutex_recs);
+       for (unsigned i=0; i<G_Recorder.frames.size(); i++) {
+               if (G_Recorder.frames.at(i) == actualFrame) {
+                       for (unsigned j=0; j<G_Recorder.global.at(i).size(); j++) {
+                               int index   = G_Recorder.global.at(i).at(j)->chan;
+                               Channel *ch = getChannelByIndex(index);
+                               ch->parseAction(G_Recorder.global.at(i).at(j), frame, actualFrame, quantize, running);
+                       }
+                       break;
+               }
        }
-       else {
+       pthread_mutex_unlock(&mutex_recs);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::doQuantize(unsigned frame)
+{
+       if (quantize < 0 || quanto <= 0) // if quantizer disabled
+               return;
+       if (actualFrame % (quanto) != 0) // if a quanto has not passed yet
+               return;
+
+       if (rewindWait) {
+               rewindWait = false;
+               rewind();
+       }
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned i=0; i<channels.size(); i++)
+               channels.at(i)->quantize(i, frame, actualFrame);  // j == localFrame
+       pthread_mutex_unlock(&mutex_chans);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::testBar(unsigned frame)
+{
+       if (actualFrame % framesPerBar != 0 || actualFrame == 0)
+               return;
+
+       if (metronome)
+               tickPlay = true;
+
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned k=0; k<channels.size(); k++)
+               channels.at(k)->onBar(frame);
+       pthread_mutex_unlock(&mutex_chans);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::testFirstBeat(unsigned frame)
+{
+       if (actualFrame != 0)
+               return;
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned k=0; k<channels.size(); k++)
+               channels.at(k)->onZero(frame, G_Conf.recsStopOnChanHalt);
+       pthread_mutex_unlock(&mutex_chans);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::testLastBeat()
+{
+       /* if actualFrame > totalFrames the sequencer returns to frame 0,
+        * beat 0. This must be the last operation. */
+
+       if (actualFrame > totalFrames) {
+               actualFrame = 0;
+               actualBeat  = 0;
+       }
+       else
+       if (actualFrame % framesPerBeat == 0 && actualFrame > 0) {
+               actualBeat++;
+
+               /* avoid tick and tock to overlap when a new bar has passed (which
+                * is also a beat) */
+
+               if (metronome && !tickPlay)
+                       tockPlay = true;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::sumChannels(unsigned frame)
+{
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned k=0; k<channels.size(); k++) {
+               if (channels.at(k)->type == CHANNEL_SAMPLE)
+                       ((SampleChannel*)channels.at(k))->sum(frame, running);
+       }
+       pthread_mutex_unlock(&mutex_chans);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::renderMetronome(float *outBuf, unsigned frame)
+{
+       if (tockPlay) {
+               outBuf[frame]   += tock[tockTracker];
+               outBuf[frame+1] += tock[tockTracker];
+               tockTracker++;
+               if (tockTracker >= TICKSIZE-1) {
+                       tockPlay    = false;
+                       tockTracker = 0;
+               }
+       }
+       if (tickPlay) {
+               outBuf[frame]   += tick[tickTracker];
+               outBuf[frame+1] += tick[tickTracker];
+               tickTracker++;
+               if (tickTracker >= TICKSIZE-1) {
+                       tickPlay    = false;
+                       tickTracker = 0;
+               }
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::renderIO(float *outBuf, float *inBuf)
+{
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned k=0; k<channels.size(); k++)
+               channels.at(k)->process(outBuf, inBuf);
+       pthread_mutex_unlock(&mutex_chans);
+
 #ifdef WITH_VST
-               G_PluginHost.processStackOffline(vChanInput, PluginHost::MASTER_IN, 0, totalFrames);
+       pthread_mutex_lock(&mutex_plugins);
+       G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT);
+       G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN);
+       pthread_mutex_unlock(&mutex_plugins);
 #endif
-               int numFrames = totalFrames*sizeof(float);
-               memcpy(chanInput->wave->data, vChanInput, numFrames);
-               memset(vChanInput, 0, numFrames); // clear vchan
-               return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::computePeak(float *outBuf, unsigned frame)
+{
+       /* TODO it takes into account only left channel so far! */
+       if (outBuf[frame] > peakOut)
+               peakOut = outBuf[frame];
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::limitOutput(float *outBuf, unsigned frame)
+{
+       if (outBuf[frame] > 1.0f)
+               outBuf[frame] = 1.0f;
+       else
+       if (outBuf[frame] < -1.0f)
+               outBuf[frame] = -1.0f;
+
+       if (outBuf[frame+1] > 1.0f)
+               outBuf[frame+1] = 1.0f;
+       else
+       if (outBuf[frame+1] < -1.0f)
+               outBuf[frame+1] = -1.0f;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::finalizeOutput(float *outBuf, unsigned frame)
+{
+       /* merge vChanInToOut, if enabled */
+
+       if (inToOut) {
+               outBuf[frame]   += vChanInToOut[frame];
+               outBuf[frame+1] += vChanInToOut[frame+1];
        }
+       outBuf[frame]   *= outVol;
+       outBuf[frame+1] *= outVol;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Mixer::clearAllBuffers(float *outBuf, unsigned bufferSize)
+{
+       memset(outBuf, 0, sizeof(float) * bufferSize);         // out
+       memset(vChanInToOut, 0, sizeof(float) * bufferSize);   // inToOut vChan
+
+       pthread_mutex_lock(&mutex_chans);
+       for (unsigned i=0; i<channels.size(); i++)
+               channels.at(i)->clear();
+       pthread_mutex_unlock(&mutex_chans);
 }
index 8387efd250b3de427683b855605eecbdcea8026d..f8afb461c481f44fff9549254735be8c175b7e85 100644 (file)
 #ifndef MIXER_H
 #define MIXER_H
 
-#include <stdlib.h>
+
 #include <pthread.h>
 #include <vector>
-#include "const.h"
 #include "kernelAudio.h"
-#include "../utils/utils.h"
-
-
-using std::vector;
 
 
 class Mixer
@@ -46,7 +41,6 @@ class Mixer
 public:
 
        Mixer();
-       ~Mixer();
 
        void init();
        int  close();
@@ -64,11 +58,9 @@ public:
        /* masterPlay
         * core method (callback) */
 
-       static int masterPlay(
-               void *out_buf, void *in_buf, unsigned n_frames,
-               double streamTime, RtAudioStreamStatus status, void *userData
-       );
-       int __masterPlay(void *out_buf, void *in_buf, unsigned n_frames);
+       static int masterPlay(void *outBuf, void *inBuf, unsigned bufferSize,
+               double streamTime, RtAudioStreamStatus status, void *userData);
+       int __masterPlay(void *outBuf, void *inBuf, unsigned bufferSize);
 
        /* updateFrameBars
         * updates bpm, frames, beats and so on. */
@@ -104,7 +96,7 @@ public:
         * memcpy the virtual channel input in the channel designed for input
         * recording. Called by mixerHandler on stopInputRec() */
 
-       bool mergeVirtualInput();
+       void mergeVirtualInput();
 
        /* getChannelByIndex
         * return channel with given index 'i'. */
@@ -131,9 +123,10 @@ public:
                XFADE   = 0x02
        };
 
-       vector<class Channel*> channels;
+       std::vector<class Channel*> channels;
 
        bool   running;
+       bool   recording;         // is recording something?
        bool   ready;
        float *vChanInput;        // virtual channel for recording
        float *vChanInToOut;      // virtual channel in->out bridge (hear what you're playin)
@@ -166,11 +159,6 @@ public:
        int  tickTracker, tockTracker;
        bool tickPlay, tockPlay; // 1 = play, 0 = stop
 
-       /* chanInput
-        * the active channel during a recording. NULL = no channels active */
-
-       class SampleChannel *chanInput;
-
        /* inputTracker
         * position of the sample in the input side (recording) */
 
@@ -210,6 +198,71 @@ private:
         * the slave */
 
        void sendMIDIrewind();
+
+       /* lineInRec
+       Records from line in. */
+
+       void lineInRec(float *inBuf, unsigned frame);
+
+       /* ProcessLineIn
+       Computes line in peaks, plus handles "hear what you're playin'" thing. */
+
+       void processLineIn(float *inBuf, unsigned frame);
+
+       /* clearAllBuffers
+       Cleans up every buffer, both in Mixer and in channels. */
+
+       void clearAllBuffers(float *outBuf, unsigned bufferSize);
+
+       /* readActions
+       Reads all recorded actions. */
+
+       void readActions(unsigned frame);
+
+       /* doQuantize
+       Computes quantization on 'rewind' button and all channels. */
+
+       void doQuantize(unsigned frame);
+
+       /* sumChannels
+       Sums channels, i.e. lets them add sample frames to their virtual channels.
+       This is required for CHANNEL_SAMPLE only */
+
+       void sumChannels(unsigned frame);
+
+       /* renderMetronome
+       Generates metronome when needed and pastes it to the output buffer. */
+
+       void renderMetronome(float *outBuf, unsigned frame);
+
+       /* renderIO
+       Final processing stage. Take each channel and process it (i.e. copy its
+       content to the output buffer). Process plugins too, if any. */
+
+       void renderIO(float *outBuf, float *inBuf);
+
+       /* limitOutput
+       Applies a very dumb hard limiter. */
+
+       void limitOutput(float *outBuf, unsigned frame);
+
+       /* computePeak */
+
+       void computePeak(float *outBuf, unsigned frame);
+
+       /* finalizeOutput
+       Last touches after the output has been rendered: apply inToOut if any, apply
+       output volume. */
+
+       void finalizeOutput(float *outBuf, unsigned frame);
+
+       /* test*
+       Checks if the sequencer has reached a specific point (bar, first beat or
+       last frame). */
+
+       void testBar(unsigned frame);
+       void testFirstBeat(unsigned frame);
+       void testLastBeat();
 };
 
 #endif
index f965e02af78161424d98e7ac6178faa893bf62ee..e3d19458ad18c74a2aee233a72993c1ed411b78d 100644 (file)
 #endif
 
 #include <vector>
-#include "../utils/utils.h"
+#include "../utils/fs.h"
+#include "../utils/string.h"
 #include "../utils/log.h"
-#include "../glue/glue.h"
+#include "../glue/main.h"
 #include "../glue/channel.h"
 #include "mixerHandler.h"
 #include "kernelMidi.h"
@@ -201,83 +202,90 @@ void mh_rewindSequencer()
 /* -------------------------------------------------------------------------- */
 
 
-SampleChannel *mh_startInputRec()
+bool mh_startInputRec()
 {
-       /* search for the next available channel */
+       int channelsReady = 0;
 
-       SampleChannel *chan = NULL;
        for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE)
-                       if (((SampleChannel*) G_Mixer.channels.at(i))->canInputRec()) {
-                       chan = (SampleChannel*) G_Mixer.channels.at(i);
-                       break;
-               }
-       }
 
-       /* no chans available? */
+               if (!G_Mixer.channels.at(i)->canInputRec())
+                       continue;
 
-       if (chan == NULL)
-               return NULL;
+               SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
 
-       Wave *w = new Wave();
-       if (!w->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate))
-               return NULL;
+               /* Allocate empty sample for the current channel. */
+
+               if (!ch->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate, G_Patch.lastTakeId))
+               {
+                       gu_log("[mh_startInputRec] unable to allocate new Wave in chan %d!\n",
+                               ch->index);
+                       continue;
+               }
+
+               /* Increase lastTakeId until the sample name TAKE-[n] is unique */
+
+               while (!mh_uniqueSampleName(ch, ch->wave->name)) {
+                       G_Patch_DEPR_.lastTakeId++;
+                       G_Patch.lastTakeId++;
+                       ch->wave->name = "TAKE-" + gu_itoa(G_Patch.lastTakeId);
+               }
 
-       /* increase lastTakeId until the sample name TAKE-[n] is unique */
+               gu_log("[mh_startInputRec] start input recs using chan %d with size %d "
+                       "frame=%d\n", ch->index, G_Mixer.totalFrames, G_Mixer.inputTracker);
 
-       char name[32];
-       sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId);
-       while (!mh_uniqueSamplename(chan, name)) {
-               G_Patch_DEPR_.lastTakeId++;
-               G_Patch.lastTakeId++;
-               sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId);
+               channelsReady++;
        }
 
-       chan->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate, G_Patch_DEPR_.lastTakeId);
-       G_Mixer.chanInput = chan;
+       if (channelsReady > 0) {
+               G_Mixer.recording = true;
+               /* start to write from the actualFrame, not the beginning */
+               /** FIXME: this should be done before wave allocation */
+               G_Mixer.inputTracker = G_Mixer.actualFrame;
+               return true;
+       }
+       return false;
+}
 
-       /* start to write from the actualFrame, not the beginning */
-       /** FIXME: move this before wave allocation*/
 
-       G_Mixer.inputTracker = G_Mixer.actualFrame;
+/* -------------------------------------------------------------------------- */
 
-       gLog(
-               "[mh] start input recs using chan %d with size %d, frame=%d\n",
-               chan->index, G_Mixer.totalFrames, G_Mixer.inputTracker
-       );
 
-       return chan;
+void mh_stopInputRec()
+{
+       G_Mixer.mergeVirtualInput();
+       G_Mixer.recording = false;
+       G_Mixer.waitRec = 0; // in case delay compensation is in use
+       gu_log("[mh] stop input recs\n");
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-SampleChannel *mh_stopInputRec()
+bool mh_hasArmedSampleChannels()
 {
-       gLog("[mh] stop input recs\n");
-       G_Mixer.mergeVirtualInput();
-       SampleChannel *ch = G_Mixer.chanInput;
-       G_Mixer.chanInput = NULL;
-       G_Mixer.waitRec   = 0;                                  // if delay compensation is in use
-       return ch;
+  for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+    Channel *ch = G_Mixer.channels.at(i);
+    if (ch->type == CHANNEL_SAMPLE && ch->armed)
+      return true;
+  }
+  return false;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-bool mh_uniqueSamplename(SampleChannel *ch, const char *name)
+bool mh_uniqueSampleName(SampleChannel *ch, const string &name)
 {
        for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-               if (ch != G_Mixer.channels.at(i)) {
-                       if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
-                               SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i);
-                               if (other->wave != NULL)
-                                       if (!strcmp(name, other->wave->name.c_str()))
-                                               return false;
-                       }
-               }
+               if (ch == G_Mixer.channels.at(i))  // skip itself
+                       continue;
+               if (G_Mixer.channels.at(i)->type != CHANNEL_SAMPLE)
+                       continue;
+               SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i);
+               if (other->wave != NULL && name == other->wave->name)
+                       return false;
        }
        return true;
 }
index c624d266e35f755392dc775aaa3313ed709e375f..9c33b1c43f1800becd63aa18df95196014579e92 100644 (file)
 #define MIXERHANDLER_H
 
 
-#include <vector>
-#include "recorder.h"
-#include "patch.h"
-
-
-using std::vector;
+#include <string>
 
 
 /* stopSequencer
@@ -64,14 +59,20 @@ void mh_readPatch();
  * the chan number chosen, otherwise -1 if there are no more empty
  * channels available. */
 
-SampleChannel *mh_startInputRec();
+bool mh_startInputRec();
 
-SampleChannel *mh_stopInputRec();
+void mh_stopInputRec();
 
 /* uniqueSamplename
  * return true if samplename 'n' is unique. Requires SampleChannel *ch
  * in order to skip check against itself. */
 
-bool mh_uniqueSamplename(class SampleChannel *ch, const char *name);
+bool mh_uniqueSampleName(class SampleChannel *ch, const std::string &s);
+
+/* hasArmedSampleChannels
+Tells whether Mixer has one or more sample channels armed for input
+recording. */
+
+bool mh_hasArmedSampleChannels();
 
 #endif
index 1cc2653fb7edf907bb6a42de5093d867cf321d20..dbc1aa78e7c4ef14731aa0985ed567316bf1c05a 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <stdint.h>
 #include "../utils/log.h"
-#include "../utils/utils.h"
-#include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/elems/ge_keyboard.h"
-#include "patch.h"
+#include "../utils/string.h"
 #include "const.h"
-#include "init.h"
-#include "recorder.h"
 #include "conf.h"
-#include "wave.h"
 #include "mixer.h"
-#include "channel.h"
+#include "patch.h"
 
 
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern gdMainWindow *mainWin;
+extern Mixer G_Mixer;
+extern Conf  G_Conf;
 
 
 void Patch::init()
@@ -77,7 +69,7 @@ int Patch::write(const string &file)
 #endif
 
   if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) {
-    gLog("[Patch::write] unable to write patch file!\n");
+    gu_log("[Patch::write] unable to write patch file!\n");
     return 0;
   }
   return 1;
@@ -91,7 +83,7 @@ int Patch::read(const string &file)
 {
   jRoot = json_load_file(file.c_str(), 0, &jError);
   if (!jRoot) {
-    gLog("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text);
+    gu_log("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text);
     return PATCH_UNREADABLE;
   }
 
@@ -226,6 +218,7 @@ void Patch::writeChannels(json_t *jContainer, vector<channel_t> *channels)
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     json_integer(channel.midiInKeyPress));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       json_integer(channel.midiInKeyRel));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         json_integer(channel.midiInKill));
+    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_SOLO,         json_integer(channel.midiInSolo));
@@ -296,7 +289,7 @@ bool Patch::readColumns(json_t *jContainer)
   json_t *jColumn;
   json_array_foreach(jColumns, columnIndex, jColumn) {
 
-    string columnIndexStr = "column " + gItoa(columnIndex);
+    string columnIndexStr = "column " + gu_itoa(columnIndex);
     if (!checkObject(jColumn, columnIndexStr.c_str()))
       return 0;
 
@@ -323,7 +316,7 @@ bool Patch::readChannels(json_t *jContainer)
   json_t *jChannel;
   json_array_foreach(jChannels, channelIndex, jChannel) {
 
-    string channelIndexStr = "channel " + gItoa(channelIndex);
+    string channelIndexStr = "channel " + gu_itoa(channelIndex);
     if (!checkObject(jChannel, channelIndexStr.c_str()))
       return 0;
 
@@ -342,6 +335,7 @@ bool Patch::readChannels(json_t *jContainer)
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS,     channel.midiInKeyPress)) return 0;
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL,       channel.midiInKeyRel)) return 0;
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL,         channel.midiInKill)) return 0;
+    if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          channel.midiInArm)) return 0;
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       channel.midiInVolume)) return 0;
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         channel.midiInMute)) return 0;
     if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         channel.midiInSolo)) return 0;
index ba1cd338f2d8d8ce15b16acf793ef2b63068308f..99ef6a15eeae4031df5c026ccff09d9a3afe23ec 100644 (file)
@@ -34,9 +34,7 @@
 #include <string>
 #include <vector>
 #include <stdint.h>
-#include "../utils/utils.h"
 #include "dataStorageJson.h"
-#include "const.h"
 
 
 using std::string;
@@ -79,6 +77,7 @@ public:
     uint32_t    midiInKeyPress;
     uint32_t    midiInKeyRel;
     uint32_t    midiInKill;
+    uint32_t    midiInArm;
     uint32_t    midiInVolume;
     uint32_t    midiInMute;
     uint32_t    midiInSolo;
index 7c30284faab37614e155c282a5a412a65c5b01ea..99010a02a13f9b639f3e97eaa666ddf392a68fed 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <stdint.h>
 #include "../utils/log.h"
-#include "../utils/utils.h"
+#include "../utils/fs.h"
 #include "../gui/dialogs/gd_mainWindow.h"
 #include "../gui/elems/ge_keyboard.h"
 #include "patch_DEPR_.h"
@@ -43,8 +43,9 @@
 #include "channel.h"
 
 
-extern Mixer                G_Mixer;
-extern Conf    G_Conf;
+extern Mixer             G_Mixer;
+extern Conf       G_Conf;
+extern Recorder   G_Recorder;
 #ifdef WITH_VST
 extern PluginHost G_PluginHost;
 #endif
@@ -61,7 +62,7 @@ int Patch_DEPR_::open(const char *file)
                return PATCH_INVALID;
 
        version = atof(getValue("versionf").c_str());
-       gLog("[patch_DEPR_] open patch version %f\n", version);
+       gu_log("[patch_DEPR_] open patch version %f\n", version);
 
        return PATCH_READ_OK;
 }
@@ -469,7 +470,7 @@ uint32_t Patch_DEPR_::getMidiValue(int i, const char *c)
 
 int Patch_DEPR_::readRecs()
 {
-       gLog("[patch_DEPR_] Reading recs...\n");
+       gu_log("[patch_DEPR_] Reading recs...\n");
 
        unsigned numrecs = atoi(getValue("numrecs").c_str());
 
@@ -482,7 +483,7 @@ int Patch_DEPR_::readRecs()
                sprintf(tmpbuf, "recframe%d", i);
                sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame);
 
-//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
+//gu_log("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
 
                for (int k=0; k<recPerFrame; k++) {
                        int      chan = 0;
@@ -504,15 +505,15 @@ int Patch_DEPR_::readRecs()
                                else
                                        sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%u", &chan, &type, &fValue, &iValue);
 
-//gLog("  loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
+//gu_log("  loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
 
                        Channel *ch = G_Mixer.getChannelByIndex(chan);
                        if (ch)
                                if (ch->status & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) {
                                        if (version < 0.83f)
-                                               recorder::rec(ch->index, type, frame, iValue_fix, fValue);
+                                               G_Recorder.rec(ch->index, type, frame, iValue_fix, fValue);
                                        else
-                                               recorder::rec(ch->index, type, frame, iValue, fValue);
+                                               G_Recorder.rec(ch->index, type, frame, iValue, fValue);
                                }
                }
        }
@@ -526,7 +527,7 @@ int Patch_DEPR_::readRecs()
 #ifdef WITH_VST
 int Patch_DEPR_::readPlugins()
 {
-       gLog("[patch_DEPR_] Reading plugins...\n");
+       gu_log("[patch_DEPR_] Reading plugins...\n");
 
        int globalOut = 1;
 
index 740bb706c58c8cb630b90f576feceaad18eb31d6..bf4a1c40743e053615da54423010d61ddae84249 100644 (file)
@@ -49,16 +49,16 @@ void Plugin::init()
   status = 1;
 
   if (getActiveEditor() != NULL) {
-    gLog("[Plugin::init] plugin has an already active editor!\n");
+    gu_log("[Plugin::init] plugin has an already active editor!\n");
     return;
   }
   ui = createEditorIfNeeded();
   if (ui == NULL) {
-    gLog("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n");
+    gu_log("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n");
     return;
   }
 
-  gLog("[Plugin::init] editor initialized and ready\n");
+  gu_log("[Plugin::init] editor initialized and ready\n");
 }
 
 
@@ -68,7 +68,7 @@ void Plugin::init()
 void Plugin::showEditor(void *parent)
 {
   if (ui == NULL) {
-    gLog("[Plugin::showEditor] can't show editor!\n");
+    gu_log("[Plugin::showEditor] can't show editor!\n");
     return;
   }
   ui->setOpaque(true);
index 9f31f2edaacfac3932a12ba5e01c1044869fdef6..f95a96694d261cd359e646c702678e1aa78c5c29 100644 (file)
 
 
 #include "../utils/log.h"
-#include "../utils/utils.h"
-#include "mixer.h"
+#include "const.h"
 #include "channel.h"
-#include "midiChannel.h"
 #include "plugin.h"
 #include "pluginHost.h"
 
@@ -53,7 +51,7 @@ PluginHost::~PluginHost()
 
 void PluginHost::init(int _buffersize, int _samplerate)
 {
-  gLog("[PluginHost::init] initialize with buffersize=%d, samplerate=%d\n",
+  gu_log("[PluginHost::init] initialize with buffersize=%d, samplerate=%d\n",
     _buffersize, _samplerate);
 
   messageManager = juce::MessageManager::getInstance();
@@ -62,7 +60,9 @@ void PluginHost::init(int _buffersize, int _samplerate)
   buffersize = _buffersize;
   missingPlugins = false;
   //unknownPluginList.empty();
-  loadList(gGetHomePath() + G_SLASH + "plugins.xml");
+  loadList(gu_getHomePath() + G_SLASH + "plugins.xml");
+
+  pthread_mutex_init(&mutex_midi, NULL);
 }
 
 
@@ -72,8 +72,8 @@ void PluginHost::init(int _buffersize, int _samplerate)
 int PluginHost::scanDir(const string &dirpath, void (*callback)(float progress, void *p),
     void *p)
 {
-  gLog("[PluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str());
-  gLog("[PluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
+  gu_log("[PluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str());
+  gu_log("[PluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
 
   knownPluginList.clear();   // clear up previous plugins
 
@@ -85,13 +85,13 @@ int PluginHost::scanDir(const string &dirpath, void (*callback)(float progress,
   bool cont = true;
   juce::String name;
   while (cont) {
-    gLog("[PluginHost::scanDir]   scanning '%s'\n", name.toRawUTF8());
+    gu_log("[PluginHost::scanDir]   scanning '%s'\n", name.toRawUTF8());
     cont = scanner.scanNextFile(false, name);
     if (callback)
       callback(scanner.getProgress(), p);
   }
 
-  gLog("[PluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
+  gu_log("[PluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
   return knownPluginList.getNumTypes();
 }
 
@@ -103,7 +103,7 @@ int PluginHost::saveList(const string &filepath)
 {
   int out = knownPluginList.createXml()->writeToFile(juce::File(filepath), "");
   if (!out)
-    gLog("[PluginHost::saveList] unable to save plugin list to %s\n", filepath.c_str());
+    gu_log("[PluginHost::saveList] unable to save plugin list to %s\n", filepath.c_str());
   return out;
 }
 
@@ -138,7 +138,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType,
 
   juce::PluginDescription *pd = knownPluginList.getTypeForFile(fid);
   if (!pd) {
-    gLog("[PluginHost::addPlugin] no plugin found with fid=%s!\n", fid.c_str());
+    gu_log("[PluginHost::addPlugin] no plugin found with fid=%s!\n", fid.c_str());
     missingPlugins = true;
     unknownPluginList.push_back(fid);
     return NULL;
@@ -146,7 +146,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType,
 
   Plugin *p = (Plugin *) pluginFormat.createInstanceFromDescription(*pd, samplerate, buffersize);
   if (!p) {
-    gLog("[PluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str());
+    gu_log("[PluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str());
     missingPlugins = true;
     return NULL;
   }
@@ -157,7 +157,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType,
   p->init();
   p->prepareToPlay(samplerate, buffersize);
 
-  gLog("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str());
+  gu_log("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str());
 
   /* Try to inject the plugin as soon as possible. */
 
@@ -171,7 +171,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType,
     }
   }
 
-  gLog("[PluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n",
+  gu_log("[PluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n",
     fid.c_str(), p->getName().toStdString().c_str(), stackType, pStack->size());
 
   return p;
@@ -186,12 +186,12 @@ Plugin *PluginHost::addPlugin(int index, int stackType, pthread_mutex_t *mutex,
 {
   juce::PluginDescription *pd = knownPluginList.getType(index);
   if (pd) {
-    gLog("[PluginHost::addPlugin] plugin found, uid=%s, name=%s...\n",
+    gu_log("[PluginHost::addPlugin] plugin found, uid=%s, name=%s...\n",
       pd->fileOrIdentifier.toStdString().c_str(), pd->name.toStdString().c_str());
     return addPlugin(pd->fileOrIdentifier.toStdString(), stackType, mutex, ch);
   }
   else {
-    gLog("[PluginHost::addPlugin] no plugins found at index=%d!\n", index);
+    gu_log("[PluginHost::addPlugin] no plugins found at index=%d!\n", index);
     return NULL;
   }
 }
@@ -258,7 +258,7 @@ PluginHost::PluginInfo PluginHost::getAvailablePluginInfo(int i)
   pi.isInstrument = pd->isInstrument;
 /*
   if (!p) {
-    gLog("[PluginHost::getAvailablePlugin] unable to create plugin instance!\n");
+    gu_log("[PluginHost::getAvailablePlugin] unable to create plugin instance!\n");
     return NULL;
   }
   */
@@ -303,7 +303,7 @@ void PluginHost::freeStack(int stackType, pthread_mutex_t *mutex, Channel *ch)
                        break;
                }
        }
-  gLog("[PluginHost::freeStack] stack type=%d freed\n", stackType);
+  gu_log("[PluginHost::freeStack] stack type=%d freed\n", stackType);
 }
 
 
@@ -326,17 +326,29 @@ void PluginHost::processStack(float *buffer, int stackType, Channel *ch)
     audioBuffer.setSample(1, i, buffer[(i*2)+1]);
        }
 
-       /* hardcore processing. At the end we swap input and output, so that
-        * the N-th plugin will process the result of the plugin N-1. */
+       /* Hardcore processing. At the end we swap input and output, so that he N-th
+  plugin will process the result of the plugin N-1. Part of this loop must be
+  guarded by mutexes, i.e. the MIDI process part. You definitely don't want
+  a situation like the following one:
+    processBlock(...)
+    [a new midi event from kernelMidi thread]
+    clearMidiBuffer()
+  The midi event in between would be surely lost, deleted by clearMidiBuffer! */
 
        for (unsigned i=0; i<pStack->size(); i++) {
     Plugin *plugin = pStack->at(i);
                if (plugin->getStatus() != 1 || plugin->isSuspended() || plugin->isBypassed())
                        continue;
-    juce::MidiBuffer midiBuffer;
-    if (ch) // ch might be null if stackType is MASTER_IN or MASTER_OUT
-      midiBuffer = ch->getPluginMidiEvents();
-               plugin->processBlock(audioBuffer, midiBuffer);
+    if (ch) { // ch might be null if stackType is MASTER_IN/OUT
+      pthread_mutex_lock(&mutex_midi);
+      plugin->processBlock(audioBuffer, ch->getPluginMidiEvents());
+      ch->clearMidiBuffer();
+      pthread_mutex_unlock(&mutex_midi);
+    }
+    else {
+      juce::MidiBuffer midiBuffer;  // empty buffer
+      plugin->processBlock(audioBuffer, midiBuffer);
+    }
   }
 
        /* converting buffer from Juce to Giada. A note for the future: if we
@@ -389,11 +401,11 @@ void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType,
                if (lockStatus == 0) {
                        std::swap(pStack->at(indexA), pStack->at(indexB));
                        pthread_mutex_unlock(mutex);
-                       gLog("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB);
+                       gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB);
                        return;
                }
                //else
-                       //gLog("[pluginHost] waiting for mutex...\n");
+                       //gu_log("[pluginHost] waiting for mutex...\n");
        }
 }
 
@@ -406,37 +418,30 @@ void PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex,
 {
        vector <Plugin *> *pStack = getStack(stackType, ch);
 
-       /* try to delete the plugin until succeed. G_Mixer has priority. */
-
        for (unsigned i=0; i<pStack->size(); i++) {
     Plugin *pPlugin = pStack->at(i);
-               if (pPlugin->getId() == id) {
-                       if (pPlugin->getStatus() == 0) { // no frills if plugin is missing
-                               delete pPlugin;
-                               pStack->erase(pStack->begin() + i);
-        gLog("[pluginHost::freePlugin] plugin id=%d removed with no frills, since it had status=0\n", id);
-                               return;
-                       }
-                       else {
-                               int lockStatus;
-                               while (true) {
-                                       lockStatus = pthread_mutex_trylock(mutex);
-                                       if (lockStatus == 0) {
-            pPlugin->suspendProcessing(true);
-            pPlugin->releaseResources();
-                                               delete pPlugin;
-                                               pStack->erase(pStack->begin() + i);
-                                               pthread_mutex_unlock(mutex);
-                                               gLog("[pluginHost::freePlugin] plugin id=%d removed\n", id);
-                                               return;
-                                       }
-                                       //else
-                                               //gLog("[pluginHost] waiting for mutex...\n");
-                               }
-                       }
+               if (pPlugin->getId() != id)
+      continue;
+               if (pPlugin->getStatus() == 0) { // no frills if plugin is missing
+                       delete pPlugin;
+                       pStack->erase(pStack->begin() + i);
+      gu_log("[pluginHost::freePlugin] plugin id=%d removed with no frills, since it had status=0\n", id);
+                       return;
+               }
+
+               while (true) {
+                       if (pthread_mutex_trylock(mutex) != 0)
+        continue;
+      pPlugin->suspendProcessing(true);
+      pPlugin->releaseResources();
+                       delete pPlugin;
+                       pStack->erase(pStack->begin() + i);
+                       pthread_mutex_unlock(mutex);
+                       gu_log("[pluginHost::freePlugin] plugin id=%d removed\n", id);
+                       return;
                }
   }
-       gLog("[pluginHost::freePlugin] plugin id=%d not found\n", id);
+       gu_log("[pluginHost::freePlugin] plugin id=%d not found\n", id);
 }
 
 
@@ -446,7 +451,7 @@ void PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex,
 void PluginHost::runDispatchLoop()
 {
   messageManager->runDispatchLoopUntil(10);
-  //gLog("[PluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent());
+  //gu_log("[PluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent());
 }
 
 
@@ -473,7 +478,7 @@ int PluginHost::clonePlugin(Plugin *src, int stackType, pthread_mutex_t *mutex,
   juce::PluginDescription pd = src->getPluginDescription();
        Plugin *p = addPlugin(pd.fileOrIdentifier.toStdString(), stackType, mutex, ch);
        if (!p) {
-               gLog("[PluginHost::clonePlugin] unable to add new plugin to stack!\n");
+               gu_log("[PluginHost::clonePlugin] unable to add new plugin to stack!\n");
                return 0;
        }
        for (int k=0; k<src->getNumParameters(); k++) {
@@ -513,36 +518,5 @@ void PluginHost::sortPlugins(int method)
   }
 }
 
-/* -------------------------------------------------------------------------- */
-
-
-void PluginHost::processStackOffline(float *buffer, int stackType, Channel *ch, int size)
-{
-#if 0
-       /* call processStack on the entire size of the buffer. How many cycles?
-        * size / (kernelAudio::realBufsize*2) (ie. internal bufsize) */
-
-       /** FIXME 1 - calling processStack is slow, due to its internal buffer
-        * conversions. We should also call processOffline from VST sdk */
-
-       int index = 0;
-       int step  = kernelAudio::realBufsize*2;
-
-       while (index <= size) {
-               int left = index+step-size;
-               if (left < 0)
-                       processStack(&buffer[index], stackType, ch);
-
-       /** FIXME 2 - we left out the last part of buffer, because size % step != 0.
-        * we should process the last chunk in a separate buffer, padded with 0 */
-
-               //else
-               //      gLog("chunk of buffer left, size=%d\n", left);
-
-               index+=step;
-       }
-#endif
-}
-
 
 #endif // #ifdef WITH_VST
index ac741e25cdf17425624680863aa5261653ebcc00..c1f0a515d4f91f41b6d982fc80fb0ad22ca4c96e 100644 (file)
@@ -197,11 +197,6 @@ public:
 
   void runDispatchLoop();
 
-  /* processStackOffline
-   * apply the fx list to a longer chunk of data */
-
-  void processStackOffline(float *buffer, int stackType, class Channel *ch, int size);
-
   /* freeAllStacks
    * Free everything. */
 
@@ -219,6 +214,8 @@ public:
   bool hasMissingPlugins() { return missingPlugins; };
 
   void sortPlugins(int sortMethod);
+
+  pthread_mutex_t mutex_midi;
 };
 #endif
 
index 53864b0bb36f1273dd3ec931a435426101cf07b4..57958c73d007b1c94f7de24d41e2cdd2b1824a47 100644 (file)
@@ -3,7 +3,6 @@
  * Giada - Your Hardcore Loopmachine
  *
  * recorder
- * Action recorder.
  *
  * -----------------------------------------------------------------------------
  *
@@ -29,7 +28,8 @@
 
 
 #include <math.h>
-#include "recorder.h"
+#include "../utils/log.h"
+#include "../utils/fs.h"
 #include "const.h"
 #include "mixer.h"
 #include "mixerHandler.h"
 #include "conf.h"
 #include "channel.h"
 #include "sampleChannel.h"
-#include "../utils/log.h"
-#include "../utils/utils.h"
+#include "recorder.h"
 
 
+extern KernelAudio G_KernelAudio;
 extern Mixer       G_Mixer;
-extern Patch_DEPR_ f_patch;
-extern Conf           G_Conf;
 
 
-namespace recorder
+Recorder::Recorder()
+       : active       (false),
+         sortedActions(false)
 {
-vector<int> frames;
-vector< vector<action*> > global;
-vector<action*>  actions;
-
-bool active = false;
-bool sortedActions = false;
-
-composite cmp;
-
+}
 
 /* -------------------------------------------------------------------------- */
 
 
-void init()
+void Recorder::init()
 {
        sortedActions = false;
        active = false;
@@ -74,24 +66,28 @@ void init()
 /* -------------------------------------------------------------------------- */
 
 
-bool canRec(Channel *ch)
+bool Recorder::canRec(Channel *ch)
 {
        /* NO recording if:
         * recorder is inactive
         * mixer is not running
-        * mixer is recording a take in this channel ch
+        * mixer is recording a take somewhere
         * channel is empty */
 
-       if (!active || !G_Mixer.running || G_Mixer.chanInput == ch || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL))
-               return 0;
-       return 1;
+       if (!active            ||
+                 !G_Mixer.running   ||
+                        G_Mixer.recording ||
+                       (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL)
+               )
+               return false;
+       return true;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void rec(int index, int type, int frame, uint32_t iValue, float fValue)
+void Recorder::rec(int index, int type, int frame, uint32_t iValue, float fValue)
 {
        /* make sure frame is even */
 
@@ -149,12 +145,11 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue)
        /* don't activate the channel (readActions == false), it's up to
         * the other layers */
 
-       Channel *ch = G_Mixer.getChannelByIndex(index);
-       ch->hasActions = true;
+       G_Mixer.getChannelByIndex(index)->hasActions = true;
 
        sortedActions = false;
 
-       gLog("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+       gu_log("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (0x%X) fValue=%f\n",
                a->type, a->frame, a->chan, a->iValue, a->iValue, a->fValue);
        //print();
 }
@@ -163,9 +158,9 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue)
 /* -------------------------------------------------------------------------- */
 
 
-void clearChan(int index)
+void Recorder::clearChan(int index)
 {
-       gLog("[REC] clearing chan %d...\n", index);
+       gu_log("[REC] clearing chan %d...\n", index);
 
        for (unsigned i=0; i<global.size(); i++) {      // for each frame i
                unsigned j=0;
@@ -191,9 +186,9 @@ void clearChan(int index)
 /* -------------------------------------------------------------------------- */
 
 
-void clearAction(int index, char act)
+void Recorder::clearAction(int index, char act)
 {
-       gLog("[REC] clearing action %d from chan %d...\n", act, index);
+       gu_log("[REC] clearing action %d from chan %d...\n", act, index);
        for (unsigned i=0; i<global.size(); i++) {                                              // for each frame i
                unsigned j=0;
                while (true) {                                   // for each action j of frame i
@@ -219,7 +214,8 @@ void clearAction(int index, char act)
 /* -------------------------------------------------------------------------- */
 
 
-void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue, float fValue)
+void Recorder::deleteAction(int chan, int frame, char type, bool checkValues,
+       uint32_t iValue, float fValue)
 {
        /* make sure frame is even */
 
@@ -244,6 +240,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa
                                        doit &= (a->iValue == iValue && a->fValue == fValue);
 
                                if (doit) {
+                                       // TODO - wft? just do: while (true); if (pthread_mutex_trylock(&G_Mixer.mutex_recs))
                                        int lockStatus = 0;
                                        while (lockStatus == 0) {
                                                lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs);
@@ -255,7 +252,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa
                                                        break;
                                                }
                                                else
-                                                       gLog("[REC] delete action: waiting for mutex...\n");
+                                                       gu_log("[REC] delete action: waiting for mutex...\n");
                                        }
                                }
                        }
@@ -264,11 +261,11 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa
        if (found) {
                optimize();
                setChanHasActionsStatus(chan);
-               gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+               gu_log("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
                        type, frame, chan, iValue, iValue, fValue);
        }
        else
-               gLog("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
+               gu_log("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
                        type, frame, chan, iValue, iValue, fValue);
 }
 
@@ -276,7 +273,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa
 /* -------------------------------------------------------------------------- */
 
 
-void deleteActions(int chan, int frame_a, int frame_b, char type)
+void Recorder::deleteActions(int chan, int frame_a, int frame_b, char type)
 {
        sortActions();
        vector<int> dels;
@@ -293,19 +290,12 @@ void deleteActions(int chan, int frame_a, int frame_b, char type)
 /* -------------------------------------------------------------------------- */
 
 
-void clearAll()
+void Recorder::clearAll()
 {
        while (global.size() > 0) {
                for (unsigned i=0; i<global.size(); i++) {
-                       for (unsigned k=0; k<global.at(i).size(); k++) {
-#ifdef WITH_VST
-#if 0
-                               if (global.at(i).at(k)->type == ACTION_MIDI)
-                                       free(global.at(i).at(k)->event);
-#endif
-#endif
+                       for (unsigned k=0; k<global.at(i).size(); k++)
                                free(global.at(i).at(k));                                                                       // free action
-                       }
                        global.at(i).clear();                                                                                           // free action container
                        global.erase(global.begin() + i);
                }
@@ -325,7 +315,7 @@ void clearAll()
 /* -------------------------------------------------------------------------- */
 
 
-void optimize()
+void Recorder::optimize()
 {
        /* do something until the i frame is empty. */
 
@@ -347,7 +337,7 @@ void optimize()
 /* -------------------------------------------------------------------------- */
 
 
-void sortActions()
+void Recorder::sortActions()
 {
        if (sortedActions)
                return;
@@ -365,7 +355,7 @@ void sortActions()
 /* -------------------------------------------------------------------------- */
 
 
-void updateBpm(float oldval, float newval, int oldquanto)
+void Recorder::updateBpm(float oldval, float newval, int oldquanto)
 {
        for (unsigned i=0; i<frames.size(); i++) {
 
@@ -406,7 +396,7 @@ void updateBpm(float oldval, float newval, int oldquanto)
 /* -------------------------------------------------------------------------- */
 
 
-void updateSamplerate(int systemRate, int patchRate)
+void Recorder::updateSamplerate(int systemRate, int patchRate)
 {
        /* diff ratio: systemRate / patchRate
         * e.g.  44100 / 96000 = 0.4... */
@@ -414,12 +404,12 @@ void updateSamplerate(int systemRate, int patchRate)
        if (systemRate == patchRate)
                return;
 
-       gLog("[REC] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate);
+       gu_log("[REC] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate);
 
        float ratio = systemRate / (float) patchRate;
        for (unsigned i=0; i<frames.size(); i++) {
 
-               gLog("[REC]    oldFrame = %d", frames.at(i));
+               gu_log("[REC]    oldFrame = %d", frames.at(i));
 
                float newFrame = frames.at(i);
                newFrame = floorf(newFrame * ratio);
@@ -429,7 +419,7 @@ void updateSamplerate(int systemRate, int patchRate)
                if (frames.at(i) % 2 != 0)
                        frames.at(i)++;
 
-               gLog(", newFrame = %d\n", frames.at(i));
+               gu_log(", newFrame = %d\n", frames.at(i));
        }
 
        /* update structs */
@@ -446,7 +436,7 @@ void updateSamplerate(int systemRate, int patchRate)
 /* -------------------------------------------------------------------------- */
 
 
-void expand(int old_fpb, int new_fpb)
+void Recorder::expand(int old_fpb, int new_fpb)
 {
        /* this algorithm requires multiple passages if we expand from e.g. 2
         * to 16 beats, precisely 16 / 2 - 1 = 7 times (-1 is the first group,
@@ -469,7 +459,7 @@ void expand(int old_fpb, int new_fpb)
                        }
                }
        }
-       gLog("[REC] expanded recs\n");
+       gu_log("[REC] expanded recs\n");
        //print();
 }
 
@@ -477,7 +467,7 @@ void expand(int old_fpb, int new_fpb)
 /* -------------------------------------------------------------------------- */
 
 
-void shrink(int new_fpb)
+void Recorder::shrink(int new_fpb)
 {
        /* easier than expand(): here we delete eveything beyond old_framesPerBars. */
 
@@ -496,7 +486,7 @@ void shrink(int new_fpb)
                        i++;
        }
        optimize();
-       gLog("[REC] shrinked recs\n");
+       gu_log("[REC] shrinked recs\n");
        //print();
 }
 
@@ -504,7 +494,7 @@ void shrink(int new_fpb)
 /* -------------------------------------------------------------------------- */
 
 
-void setChanHasActionsStatus(int index)
+void Recorder::setChanHasActionsStatus(int index)
 {
        Channel *ch = G_Mixer.getChannelByIndex(index);
        if (global.size() == 0) {
@@ -526,7 +516,8 @@ void setChanHasActionsStatus(int index)
 /* -------------------------------------------------------------------------- */
 
 
-int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue)
+int Recorder::getNextAction(int chan, char type, int frame, action **out,
+       uint32_t iValue)
 {
        sortActions();  // mandatory
 
@@ -540,7 +531,8 @@ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue)
                for (unsigned j=0; j<global.at(i).size(); j++) {
                        action *a = global.at(i).at(j);
                        if (a->chan == chan && (type & a->type) == a->type) {
-                               if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) {
+                               //if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) {
+                               if (iValue == 0 || (iValue != 0 && (iValue & a->iValue) == a->iValue )) {
                                        *out = global.at(i).at(j);
                                        return 1;
                                }
@@ -554,7 +546,7 @@ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue)
 /* -------------------------------------------------------------------------- */
 
 
-int getAction(int chan, char action, int frame, struct action **out)
+int Recorder::getAction(int chan, char action, int frame, struct action **out)
 {
        for (unsigned i=0; i<global.size(); i++)
                for (unsigned j=0; j<global.at(i).size(); j++)
@@ -572,7 +564,7 @@ int getAction(int chan, char action, int frame, struct action **out)
 /* -------------------------------------------------------------------------- */
 
 
-void startOverdub(int index, char actionMask, int frame)
+void Recorder::startOverdub(int index, char actionMask, int frame)
 {
        /* prepare the composite struct */
 
@@ -598,10 +590,10 @@ void startOverdub(int index, char actionMask, int frame)
        int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act);
        if (res == 1) {
                if (act->type == cmp.a2.type) {
-                       int truncFrame = cmp.a1.frame-kernelAudio::realBufsize;
+                       int truncFrame = cmp.a1.frame - G_KernelAudio.realBufsize;
                        if (truncFrame < 0)
                                truncFrame = 0;
-                       gLog("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type);
+                       gu_log("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type);
                        rec(index, cmp.a2.type, truncFrame);
                }
        }
@@ -614,7 +606,7 @@ void startOverdub(int index, char actionMask, int frame)
 /* -------------------------------------------------------------------------- */
 
 
-void stopOverdub(int frame)
+void Recorder::stopOverdub(int frame)
 {
        cmp.a2.frame  = frame;
        bool ringLoop = false;
@@ -625,13 +617,13 @@ void stopOverdub(int frame)
 
        if (cmp.a2.frame < cmp.a1.frame) {
                ringLoop = true;
-               gLog("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
+               gu_log("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
                rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames);     // record at the end of the sequencer
        }
        else
        if (cmp.a2.frame == cmp.a1.frame) {
                nullLoop = true;
-               gLog("[REC]  null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
+               gu_log("[REC]  null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
                deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values
        }
 
@@ -655,7 +647,7 @@ void stopOverdub(int frame)
                int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act);
                if (res == 1) {
                        if (act->type == cmp.a2.type) {
-                               gLog("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type);
+                               gu_log("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type);
                                deleteAction(act->chan, act->frame, act->type, false); // false == don't check values
                        }
                }
@@ -666,15 +658,13 @@ void stopOverdub(int frame)
 /* -------------------------------------------------------------------------- */
 
 
-void print()
+void Recorder::print()
 {
-       gLog("[REC] ** print debug **\n");
+       gu_log("[REC] ** print debug **\n");
        for (unsigned i=0; i<global.size(); i++) {
-               gLog("  frame %d\n", frames.at(i));
+               gu_log("  frame %d\n", frames.at(i));
                for (unsigned j=0; j<global.at(i).size(); j++) {
-                       gLog("    action %d | chan %d | frame %d\n", global.at(i).at(j)->type, global.at(i).at(j)->chan, global.at(i).at(j)->frame);
+                       gu_log("    action %d | chan %d | frame %d\n", global.at(i).at(j)->type, global.at(i).at(j)->chan, global.at(i).at(j)->frame);
                }
        }
 }
-
-} // namespace
index 95a8b65c3a43d5f57ae20ca03bec08dfd03ce0a7..307b408367a44d1abff1d859a18aaf8fee599f23 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * recorder
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
+
 
 #ifndef RECORDER_H
 #define RECORDER_H
 
-#include <stdio.h>
-#include <stdlib.h>
+
+#ifdef __APPLE__  // our compiler still doesn't know about cstdint (c++11 stuff)
+       #include <stdint.h>
+#else
+       #include <cstdint>
+#endif
 #include <vector>
-#include "../utils/utils.h"
-#include "const.h"
-#include "mixer.h"
 
 
 using std::vector;
 
 
-/*
- * [global0]-->[vector<_action*>0]-->[a0][a1][a2]                              0[frames1]
- * [global1]-->[vector<_action*>1]-->[a0][a1][a2]                              1[frames2]
- * [global2]-->[vector<_action*>2]-->[a0][a1][a2]                              2[frames3]
- * [global3]-->[vector<_action*>3]-->[a0][a1][a2]                              3[frames4]
- * */
-
-namespace recorder
+class Recorder
 {
-/* action
- * struct containing fields to describe an atomic action. Note from
- * VST sdk: parameter values, like all VST parameters, are declared as
- * floats with an inclusive range of 0.0 to 1.0 (fValue). */
+public:
 
-struct action
-{
-       int      chan;    // channel index, i.e. Channel->index
-       int      type;
-       int      frame;   // redundant info, used by helper functions
-       float    fValue;  // used only for envelopes (volumes, vst params).
-       uint32_t iValue;  // used only for MIDI events
-};
+       Recorder();
 
-/* composite
- * a group of two actions (keypress+keyrel, muteon+muteoff) used during
- * the overdub process */
+       /* action
+        * struct containing fields to describe an atomic action. Note from
+        * VST sdk: parameter values, like all VST parameters, are declared as
+        * floats with an inclusive range of 0.0 to 1.0 (fValue). */
 
-struct composite
-{
-       action a1;
-       action a2;
-};
+       struct action
+       {
+               int      chan;    // channel index, i.e. Channel->index
+               int      type;
+               int      frame;   // redundant info, used by helper functions
+               float    fValue;  // used only for envelopes (volumes, vst params).
+               uint32_t iValue;  // used only for MIDI events
+       };
+
+       /* [global0]-->[vector<_action*>0]-->[a0][a1][a2]                               0[frames1]
+        * [global1]-->[vector<_action*>1]-->[a0][a1][a2]                               1[frames2]
+        * [global2]-->[vector<_action*>2]-->[a0][a1][a2]                               2[frames3]
+        * [global3]-->[vector<_action*>3]-->[a0][a1][a2]                               3[frames4] */
+
+       vector<int>  frames;                                      // frame counter (sentinel) frames.size == global.size
+       vector<vector<action*>> global; // container of containers of actions
+       vector<action*> actions;                                // container of actions
 
-extern vector<int>  frames;                                          // frame counter (sentinel) frames.size == global.size
-extern vector< vector<action*> > global;       // container of containers of actions
-extern vector<action*>  actions;                                   // container of actions
+       bool active;
+       bool sortedActions;             // are actions sorted via sortActions()?
 
-extern bool active;
-extern bool sortedActions;                  // are actions sorted via sortActions()?
+       /* init
+        * everything starts from here. */
 
-/* init
- * everything starts from here. */
+       void init();
 
-void init();
+       /* setChanHasActionsStatus
+        * Check if the channel has at least one action recorded. If false, sets
+        * ch->hasActions = false. Used after an action deletion. */
 
-/* setChanHasActionsStatus
- * Check if the channel has at least one action recorded. If false, sets
- * ch->hasActions = false. Used after an action deletion. */
+       void setChanHasActionsStatus(int chan);
 
-void setChanHasActionsStatus(int chan);
+       /* canRec
+        * can a channel rec an action? Call this one BEFORE rec(). */
 
-/* canRec
- * can a channel rec an action? Call this one BEFORE rec(). */
+       bool canRec(class Channel *ch);
 
-bool canRec(Channel *ch);
+       /* rec
+        * record an action. */
 
-/* rec
- * record an action. */
+       void rec(int chan, int action, int frame, uint32_t iValue=0,
+               float fValue=0.0f);
 
-void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f);
+       /* clearChan
+        * clear all actions from a channel. */
 
-/* clearChan
- * clear all actions from a channel. */
+       void clearChan(int chan);
 
-void clearChan(int chan);
+       /* clearAction
+        * clear the 'action' action type from a channel. */
 
-/* clearAction
- * clear the 'action' action type from a channel. */
+       void clearAction(int chan, char action);
 
-void clearAction(int chan, char action);
+       /* deleteAction
+        * delete ONE action. Useful in the action editor. 'type' can be a mask. */
 
-/* deleteAction
- * delete ONE action. Useful in the action editor. 'type' can be a mask. */
+       void deleteAction(int chan, int frame, char type, bool checkValues,
+               uint32_t iValue=0, float fValue=0.0);
 
-void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue=0, float fValue=0.0);
+       /* deleteActions
+        * delete A RANGE of actions from frame_a to frame_b in channel 'chan'.
+        * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */
 
-/* deleteActions
- * delete A RANGE of actions from frame_a to frame_b in channel 'chan'.
- * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */
+       void deleteActions(int chan, int frame_a, int frame_b, char type);
 
-void deleteActions(int chan, int frame_a, int frame_b, char type);
+       /* clearAll
+        * delete everything. */
 
-/* clearAll
- * delete everything. */
+       void clearAll();
 
-void clearAll();
+       /* optimize
+        * clear frames without actions. */
 
-/* optimize
- * clear frames without actions. */
+       void optimize();
 
-void optimize();
+       /* sortActions
+        * sorts actions by frame, asc mode. */
 
-/* sortActions
- * sorts actions by frame, asc mode. */
+       void sortActions();
 
-void sortActions();
+       /* updateBpm
+        * reassign frames by calculating the new bpm value. */
 
-/* updateBpm
- * reassign frames by calculating the new bpm value. */
+       void updateBpm(float oldval, float newval, int oldquanto);
 
-void updateBpm(float oldval, float newval, int oldquanto);
+       /* updateSamplerate
+        * reassign frames taking in account the samplerate. If f_system ==
+        * f_patch nothing changes, otherwise the conversion is mandatory. */
 
-/* updateSamplerate
- * reassign frames taking in account the samplerate. If f_system ==
- * f_patch nothing changes, otherwise the conversion is mandatory. */
+       void updateSamplerate(int systemRate, int patchRate);
 
-void updateSamplerate(int systemRate, int patchRate);
+       void expand(int old_fpb, int new_fpb);
+       void shrink(int new_fpb);
 
-void expand(int old_fpb, int new_fpb);
-void shrink(int new_fpb);
+       /* getNextAction
+        * Return the nearest action in chan 'chan' of type 'action' starting
+        * from 'frame'. Action can be a bitmask. If iValue != 0 search for
+        * next action with iValue == iValue: useful for MIDI key_release. iValue
+        * can be a bitmask. */
 
-/* getNextAction
- * return the nearest action in chan 'chan' of type 'action' starting
- * from 'frame'. Action can be a bitmask. If iValue != -1 search for
- * next action with iValue == iValue: useful for MIDI key_release. */
+       int getNextAction(int chan, char action, int frame, struct action **out,
+               uint32_t iValue=0);
 
-int getNextAction(int chan, char action, int frame, struct action **out, uint32_t iValue=0);
+       /* getAction
+        * return a pointer to action in chan 'chan' of type 'action' at frame
+        * 'frame'. */
 
-/* getAction
- * return a pointer to action in chan 'chan' of type 'action' at frame
- * 'frame'. */
+       int getAction(int chan, char action, int frame, struct action **out);
 
-int getAction(int chan, char action, int frame, struct action **out);
+       /* start/endOverdub */
 
-/* start/endOverdub */
+       void startOverdub(int chan, char action, int frame);
+       void stopOverdub(int frame);
 
-void startOverdub(int chan, char action, int frame);
-void stopOverdub(int frame);
+private:
 
-/* print
- * debug of the frame stack. */
+       /* composite
+        * a group of two actions (keypress+keyrel, muteon+muteoff) used during
+        * the overdub process */
 
-void print();
+       struct composite
+       {
+               action a1;
+               action a2;
+       } cmp;
 
-}  // namespace
+       /* print
+        * debug of the frame stack. */
+
+       void print();
+
+};
 
 #endif
index 3b7d5e1984ceb849c4b837c172460571fad62eee..4489801700cba2fbb762298b54ce335edb5426bb 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <math.h>
 #include "../utils/log.h"
+#include "../utils/string.h"
 #include "sampleChannel.h"
 #include "patch_DEPR_.h"
 #include "patch.h"
 #include "waveFx.h"
 #include "mixerHandler.h"
 #include "kernelMidi.h"
+#include "kernelAudio.h"
 
 
 using std::string;
 
 
+extern Recorder    G_Recorder;
+extern KernelAudio G_KernelAudio;
+
+
 SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf)
        : Channel          (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize, midiMapConf),
                frameRewind      (-1),
@@ -60,12 +66,12 @@ SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf)
                fadeoutVol       (1.0f),
                fadeoutTracker   (0),
                fadeoutStep      (DEFAULT_FADEOUT_STEP),
-         readActions      (true),
+         readActions      (false),
          midiInReadActions(0x0),
          midiInPitch      (0x0)
 {
        rsmp_state = src_new(SRC_LINEAR, 2, NULL);
-       pChan      = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float));
+       pChan      = (float *) malloc(G_KernelAudio.realBufsize * 2 * sizeof(float));
 }
 
 
@@ -119,8 +125,8 @@ void SampleChannel::generateUniqueSampleName()
 {
        string oldName = wave->name;
        int k = 1; // Start from k = 1, zero is too nerdy
-       while (!mh_uniqueSamplename(this, wave->name.c_str())) {
-               wave->updateName((oldName + "-" + gItoa(k)).c_str());
+       while (!mh_uniqueSampleName(this, wave->name)) {
+               wave->updateName((oldName + "-" + gu_itoa(k)).c_str());
                k++;
        }
 }
@@ -140,7 +146,7 @@ void SampleChannel::clear()
        if (status & (STATUS_PLAY | STATUS_ENDING)) {
                tracker = fillChan(vChan, tracker, 0);
                if (fadeoutOn && fadeoutType == XFADE) {
-                       gLog("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker);
+                       gu_log("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker);
                        fadeoutTracker = fillChan(pChan, fadeoutTracker, 0);
                }
        }
@@ -154,14 +160,14 @@ void SampleChannel::calcVolumeEnv(int frame)
 {
        /* method: check this frame && next frame, then calculate delta */
 
-       recorder::action *a0 = NULL;
-       recorder::action *a1 = NULL;
+       Recorder::action *a0 = NULL;
+       Recorder::action *a1 = NULL;
        int res;
 
        /* get this action on frame 'frame'. It's unlikely that the action
         * is not found. */
 
-       res = recorder::getAction(index, ACTION_VOLUME, frame, &a0);
+       res = G_Recorder.getAction(index, ACTION_VOLUME, frame, &a0);
        if (res == 0)
                return;
 
@@ -170,10 +176,10 @@ void SampleChannel::calcVolumeEnv(int frame)
         * and use action at frame number 0 (actions[0]).
         * res == -2 ACTION_VOLUME not found. This should never happen */
 
-       res = recorder::getNextAction(index, ACTION_VOLUME, frame, &a1);
+       res = G_Recorder.getNextAction(index, ACTION_VOLUME, frame, &a1);
 
        if (res == -1)
-               res = recorder::getAction(index, ACTION_VOLUME, 0, &a1);
+               res = G_Recorder.getAction(index, ACTION_VOLUME, 0, &a1);
 
        volume_i = a0->fValue;
        volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f;
@@ -278,7 +284,7 @@ void SampleChannel::rewind()
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::parseAction(recorder::action *a, int localFrame,
+void SampleChannel::parseAction(Recorder::action *a, int localFrame,
                int globalFrame, int quantize, bool mixerIsRunning)
 {
        if (readActions == false)
@@ -287,7 +293,7 @@ void SampleChannel::parseAction(recorder::action *a, int localFrame,
        switch (a->type) {
                case ACTION_KEYPRESS:
                        if (mode & SINGLE_ANY)
-                               start(localFrame, false, quantize, mixerIsRunning);
+                               start(localFrame, false, quantize, mixerIsRunning, false, false);
                        break;
                case ACTION_KEYREL:
                        if (mode & SINGLE_ANY)
@@ -494,11 +500,11 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame)
        /* this is the moment in which we record the keypress, if the
         * quantizer is on. SINGLE_PRESS needs overdub */
 
-       if (recorder::canRec(this)) {
+       if (G_Recorder.canRec(this)) {
                if (mode == SINGLE_PRESS)
-                       recorder::startOverdub(index, ACTION_KEYS, globalFrame);
+                       G_Recorder.startOverdub(index, ACTION_KEYS, globalFrame);
                else
-                       recorder::rec(index, ACTION_KEYPRESS, globalFrame);
+                       G_Recorder.rec(index, ACTION_KEYPRESS, globalFrame);
        }
 }
 
@@ -603,13 +609,9 @@ void SampleChannel::calcFadeoutStep()
 
 void SampleChannel::setReadActions(bool v, bool recsStopOnChanHalt)
 {
-       if (v)
-               readActions = true;
-       else {
-               readActions = false;
-               if (recsStopOnChanHalt)
-                       kill(0);  /// FIXME - wrong frame value
-       }
+       readActions = v;
+       if (!readActions && recsStopOnChanHalt)
+               kill(0);  /// FIXME - wrong frame value
 }
 
 
@@ -643,7 +645,7 @@ void SampleChannel::setFadeOut(int actionPostFadeout)
 
 void SampleChannel::setXFade(int frame)
 {
-       gLog("[xFade] frame=%d tracker=%d\n", frame, tracker);
+       gu_log("[xFade] frame=%d tracker=%d\n", frame, tracker);
 
        calcFadeoutStep();
        fadeoutOn      = true;
@@ -697,7 +699,7 @@ void SampleChannel::pushWave(Wave *w)
 {
        wave   = w;
        status = STATUS_OFF;
-       sendMidiLplay();
+       sendMidiLplay();     // FIXME - why here?!?!
        begin  = 0;
        end    = wave->size;
 }
@@ -712,14 +714,14 @@ bool SampleChannel::allocEmpty(int frames, int samplerate, int takeId)
        if (!w->allocEmpty(frames, samplerate))
                return false;
 
-       w->name     = "TAKE-" + gItoa(takeId);
-       w->pathfile = gGetCurrentPath() + G_SLASH + w->name;
+       w->name     = "TAKE-" + gu_itoa(takeId);
+       w->pathfile = gu_getCurrentPath() + G_SLASH + w->name;
        wave        = w;
        status      = STATUS_OFF;
        begin       = 0;
        end         = wave->size;
 
-       sendMidiLplay();
+       sendMidiLplay();  // FIXME - why here?!?!
 
        return true;
 }
@@ -728,15 +730,24 @@ bool SampleChannel::allocEmpty(int frames, int samplerate, int takeId)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::process(float *buffer)
+void SampleChannel::process(float *outBuffer, float *inBuffer)
 {
+       /* If armed and inbuffer is not null (i.e. input device available), copy input
+       buffer to vChan: this enables the live recording mode. The vChan will be
+       overwritten later by PluginHost::processStack, so that you would record "clean"
+       audio (i.e. not plugin-processed). */
+
+       if (armed && inBuffer)
+    for (int i=0; i<bufferSize; i++)
+      vChan[i] += inBuffer[i]; // add, don't overwrite (no raw memcpy)
+
 #ifdef WITH_VST
        pluginHost->processStack(vChan, PluginHost::CHANNEL, this);
 #endif
 
        for (int j=0; j<bufferSize; j+=2) {
-               buffer[j]   += vChan[j]   * volume * panLeft  * boost;
-               buffer[j+1] += vChan[j+1] * volume * panRight * boost;
+               outBuffer[j]   += vChan[j]   * volume * panLeft  * boost;
+               outBuffer[j+1] += vChan[j+1] * volume * panRight * boost;
        }
 }
 
@@ -808,8 +819,8 @@ void SampleChannel::stop()
 
 int SampleChannel::load(const char *file, int samplerate, int rsmpQuality)
 {
-       if (strcmp(file, "") == 0 || gIsDir(file)) {
-               gLog("[SampleChannel] file not specified\n");
+       if (strcmp(file, "") == 0 || gu_isDir(file)) {
+               gu_log("[SampleChannel] file not specified\n");
                return SAMPLE_LEFT_EMPTY;
        }
 
@@ -819,13 +830,13 @@ int SampleChannel::load(const char *file, int samplerate, int rsmpQuality)
        Wave *w = new Wave();
 
        if (!w->open(file)) {
-               gLog("[SampleChannel] %s: read error\n", file);
+               gu_log("[SampleChannel] %s: read error\n", file);
                delete w;
                return SAMPLE_READ_ERROR;
        }
 
        if (w->channels() > 2) {
-               gLog("[SampleChannel] %s: unsupported multichannel wave\n", file);
+               gu_log("[SampleChannel] %s: unsupported multichannel wave\n", file);
                delete w;
                return SAMPLE_MULTICHANNEL;
        }
@@ -839,7 +850,7 @@ int SampleChannel::load(const char *file, int samplerate, int rsmpQuality)
                wfx_monoToStereo(w);
 
        if (w->rate() != samplerate) {
-               gLog("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n",
+               gu_log("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n",
                                w->rate(), samplerate);
                w->resample(rsmpQuality, samplerate);
        }
@@ -847,7 +858,7 @@ int SampleChannel::load(const char *file, int samplerate, int rsmpQuality)
        pushWave(w);
        generateUniqueSampleName();
 
-       gLog("[SampleChannel] %s loaded in channel %d\n", file, index);
+       gu_log("[SampleChannel] %s loaded in channel %d\n", file, index);
        return SAMPLE_LOADED_OK;
 }
 
@@ -944,8 +955,8 @@ int SampleChannel::readPatch(const string &basePath, int i, Patch *patch,
 
 
 bool SampleChannel::canInputRec()
-       {
-       return wave == NULL;
+{
+       return wave == NULL && armed;
 }
 
 
@@ -953,7 +964,7 @@ bool SampleChannel::canInputRec()
 
 
 void SampleChannel::start(int frame, bool doQuantize, int quantize,
-               bool mixerIsRunning)
+               bool mixerIsRunning, bool forceStart, bool isUserGenerated)
 {
        switch (status) {
                case STATUS_EMPTY:
@@ -962,35 +973,34 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize,
                {
                        return;
                }
-
                case STATUS_OFF:
                {
                        if (mode & LOOP_ANY) {
-                               status = STATUS_WAIT;
+        if (forceStart) {
+          status = STATUS_PLAY;
+          tracker = frame;
+        }
+        else
+                                   status = STATUS_WAIT;
                                sendMidiLplay();
                        }
                        else {
                                if (quantize > 0 && mixerIsRunning && doQuantize)
                                        qWait = true;
                                else {
-
-                                       /* fillChan only if frame != 0. If you call fillChan on frame == 0
-                                       a duplicate call to fillChan occurs with loss of data. Yeah, but
-                                       what happens if an action really occurs on frame 0 (and it happens,
-                                       for example     when you start the sequencer from the firt beat)? Cheat
-                                       time! Shift a little bit the frame, so that it's no longer zero.  */
-
                                        status = STATUS_PLAY;
                                        sendMidiLplay();
-                                       if (frame == 0)
-                                               frame = 2;
-                                       //if (frame != 0)
+
+                                       /* Do fillChan only if this is not a user-generated event (i.e. is an
+                                       action read by Mixer). Otherwise clear() will take take of calling
+                                       fillChan on the next cycle. */
+
+                                       if (!isUserGenerated)
                                                tracker = fillChan(vChan, tracker, frame);
                                }
                        }
                        break;
                }
-
                case STATUS_PLAY:
                {
                        if (mode == SINGLE_BASIC)
@@ -1009,14 +1019,12 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize,
                        }
                        break;
                }
-
                case STATUS_WAIT:
                {
                        status = STATUS_OFF;
                        sendMidiLplay();
                        break;
                }
-
                case STATUS_ENDING:
                {
                        status = STATUS_PLAY;
@@ -1032,13 +1040,15 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize,
 
 int SampleChannel::writePatch(int i, bool isProject, Patch *patch)
 {
+       // TODO - this code belongs to an upper level (glue)
+
        int pchIndex = Channel::writePatch(i, isProject, patch);
        Patch::channel_t *pch = &patch->channels.at(pchIndex);
 
        if (wave != NULL) {
                pch->samplePath = wave->pathfile;
                if (isProject)
-                       pch->samplePath = gBasename(wave->pathfile);  // make it portable
+                       pch->samplePath = gu_basename(wave->pathfile);  // make it portable
        }
        else
                pch->samplePath = "";
index 91582481bd82c15705d4c07d6369fb2ecd82aefe..751b99959d8f9815fd279ba38092ca0438b8bd2c 100644 (file)
@@ -89,30 +89,33 @@ public:
        SampleChannel(int bufferSize, class MidiMapConf *midiMapConf);
        ~SampleChannel();
 
-       void copy(const Channel *src, pthread_mutex_t *pluginMutex);
-
-       void clear      ();
-       void process    (float *buffer);
-       void start      (int frame, bool doQuantize, int quantize, bool mixerIsRunning);
-       void kill       (int frame);
-       void empty      ();
-       void stopBySeq  (bool chansStopOnSeqHalt);
-       void stop       ();
-       void rewind     ();
-       void setMute    (bool internal);
-       void unsetMute  (bool internal);
-       void reset      (int frame);
-       int  load       (const char *file, int samplerate, int rsmpQuality);
-       int  readPatch_DEPR_  (const char *file, int i, class Patch_DEPR_ *patch,
-                       int samplerate, int rsmpQuality);
-  int  readPatch  (const string &basePath, int i, class Patch *patch,
-                       pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality);
-       int  writePatch (int i, bool isProject, class Patch *patch);
-       void quantize   (int index, int localFrame, int globalFrame);
-       void onZero     (int frame, bool recsStopOnChanHalt);
-       void onBar      (int frame);
-       void parseAction(recorder::action *a, int localFrame, int globalFrame,
-                       int quantize, bool mixerIsRunning);
+       void copy(const Channel *src, pthread_mutex_t *pluginMutex) override;
+       void clear() override;
+       void process(float *outBuffer, float *inBuffer) override;
+       void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning,
+               bool forceStart, bool isUserGenerated) override;
+       void kill(int frame) override;
+       void empty() override;
+       void stopBySeq(bool chansStopOnSeqHalt) override;
+       void stop() override;
+       void rewind() override;
+       void setMute(bool internal) override;
+       void unsetMute(bool internal) override;
+       int readPatch_DEPR_(const char *file, int i, class Patch_DEPR_ *patch,
+                       int samplerate, int rsmpQuality) override;
+  int readPatch(const string &basePath, int i, class Patch *patch,
+                       pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override;
+       int writePatch(int i, bool isProject, class Patch *patch) override;
+       void quantize(int index, int localFrame, int globalFrame) override;
+       void onZero(int frame, bool recsStopOnChanHalt) override;
+       void onBar(int frame) override;
+       void parseAction(Recorder::action *a, int localFrame, int globalFrame,
+                       int quantize, bool mixerIsRunning) override;
+       bool canInputRec() override;
+
+       int load(const char *file, int samplerate, int rsmpQuality);
+
+       void reset(int frame);
 
        /* fade methods
         * prepare channel for fade, mixer will take care of the process
@@ -165,13 +168,8 @@ public:
 
        bool allocEmpty(int frames, int samplerate, int takeId);
 
-       /* canInputRec
-        * true if channel can host a new wave from input recording. */
-
-       bool  canInputRec();
-
        /* setReadActions
-        * if enabled, recorder will read actions from this channel. If
+        * if enabled (v == true), recorder will read actions from this channel. If
         * recsStopOnChanHalt == true, stop reading actions right away. */
 
        void setReadActions(bool v, bool recsStopOnChanHalt);
index 4bdffc917e461d5ceb2e5ef8795c1ac75c39edd5..7f89e32002540fe4895d57fb707c964868eaf351 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <string.h>  // memcpy
 #include <math.h>
-#include "../utils/utils.h"
+#include "../utils/fs.h"
 #include "../utils/log.h"
 #include "init.h"
 #include "const.h"
@@ -81,11 +81,11 @@ Wave::Wave(const Wave &other)
 int Wave::open(const char *f)
 {
        pathfile = f;
-       name     = gStripExt(gBasename(f).c_str());
+       name     = gu_stripExt(gu_basename(f));
        fileIn   = sf_open(f, SFM_READ, &inHeader);
 
        if (fileIn == NULL) {
-               gLog("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn));
+               gu_log("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn));
                pathfile = "";
                name     = "";
                return 0;
@@ -119,12 +119,12 @@ int Wave::readData()
        size = inHeader.frames * inHeader.channels;
        data = (float *) malloc(size * sizeof(float));
        if (data == NULL) {
-               gLog("[wave] unable to allocate memory\n");
+               gu_log("[wave] unable to allocate memory\n");
                return 0;
        }
 
        if (sf_read_float(fileIn, data, size) != size)
-               gLog("[wave] warning: incomplete read!\n");
+               gu_log("[wave] warning: incomplete read!\n");
 
        sf_close(fileIn);
        return 1;
@@ -144,13 +144,13 @@ int Wave::writeData(const char *f)
 
        fileOut = sf_open(f, SFM_WRITE, &outHeader);
        if (fileOut == NULL) {
-               gLog("[wave] unable to open %s for exporting\n", f);
+               gu_log("[wave] unable to open %s for exporting\n", f);
                return 0;
        }
 
        int out = sf_write_float(fileOut, data, size);
        if (out != (int) size) {
-               gLog("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut));
+               gu_log("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut));
                return 0;
        }
 
@@ -186,7 +186,7 @@ int Wave::allocEmpty(unsigned __size, unsigned samplerate)
        size = __size;
        data = (float *) malloc(size * sizeof(float));
        if (data == NULL) {
-               gLog("[wave] unable to allocate memory\n");
+               gu_log("[wave] unable to allocate memory\n");
                return 0;
        }
 
@@ -213,7 +213,7 @@ int Wave::resample(int quality, int newRate)
 
        float *tmp = (float *) malloc(newSize * sizeof(float));
        if (!tmp) {
-               gLog("[wave] unable to allocate memory for resampling\n");
+               gu_log("[wave] unable to allocate memory for resampling\n");
                return -1;
        }
 
@@ -224,11 +224,11 @@ int Wave::resample(int quality, int newRate)
        src_data.output_frames = newSize/2;  // in frames, i.e. /2 (stereo)
        src_data.src_ratio     = ratio;
 
-       gLog("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2);
+       gu_log("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2);
 
        int ret = src_simple(&src_data, quality, 2);
        if (ret != 0) {
-               gLog("[wave] resampling error: %s\n", src_strerror(ret));
+               gu_log("[wave] resampling error: %s\n", src_strerror(ret));
                return 0;
        }
 
@@ -245,12 +245,12 @@ int Wave::resample(int quality, int newRate)
 
 string Wave::basename(bool ext) const
 {
-       return ext ? gBasename(pathfile) : gStripExt(gBasename(pathfile));
+       return ext ? gu_basename(pathfile) : gu_stripExt(gu_basename(pathfile));
 }
 
 string Wave::extension() const
 {
-       return gGetExt(pathfile.c_str());
+       return gu_getExt(pathfile);
 }
 
 
@@ -259,9 +259,9 @@ string Wave::extension() const
 
 void Wave::updateName(const char *n)
 {
-       string ext = gGetExt(pathfile.c_str());
-       name       = gStripExt(gBasename(n).c_str());
-       pathfile   = gDirname(pathfile.c_str()) + G_SLASH + name + "." + ext;
+       string ext = gu_getExt(pathfile);
+       name       = gu_stripExt(gu_basename(n));
+       pathfile   = gu_dirname(pathfile) + G_SLASH + name + "." + ext;
        isLogical  = true;
 
        /* a wave with updated name must become logical, since the underlying
index 52b6f1ce32a71caa0a775b335021029afcebc5ba..58319684749dcbd05f64c05b8c6a5fd434625d75 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * waveFx
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
-#include <math.h>
+#include <cmath>
 #include "../utils/log.h"
-#include "waveFx.h"
-#include "channel.h"
-#include "mixer.h"
 #include "wave.h"
+#include "waveFx.h"
 
 
-extern Mixer G_Mixer;
-
-
-float wfx_normalizeSoft(Wave *w) {
+float wfx_normalizeSoft(Wave *w)
+{
        float peak = 0.0f;
        float abs  = 0.0f;
        for (int i=0; i<w->size; i++) { // i++: both L and R samples
@@ -57,15 +53,15 @@ float wfx_normalizeSoft(Wave *w) {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-bool wfx_monoToStereo(Wave *w) {
 
+bool wfx_monoToStereo(Wave *w)
+{
        unsigned newSize = w->size * 2;
        float *dataNew = (float *) malloc(newSize * sizeof(float));
        if (dataNew == NULL) {
-               gLog("[wfx] unable to allocate memory for mono>stereo conversion\n");
+               gu_log("[wfx] unable to allocate memory for mono>stereo conversion\n");
                return 0;
        }
 
@@ -85,16 +81,16 @@ bool wfx_monoToStereo(Wave *w) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void wfx_silence(Wave *w, int a, int b) {
-
+void wfx_silence(Wave *w, int a, int b)
+{
        /* stereo values */
        a = a * 2;
        b = b * 2;
 
-       gLog("[wfx] silencing from %d to %d\n", a, b);
+       gu_log("[wfx] silencing from %d to %d\n", a, b);
 
        for (int i=a; i<b; i+=2) {
                w->data[i]   = 0.0f;
@@ -107,10 +103,11 @@ void wfx_silence(Wave *w, int a, int b) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int wfx_cut(Wave *w, int a, int b) {
+int wfx_cut(Wave *w, int a, int b)
+{
        a = a * 2;
        b = b * 2;
 
@@ -123,11 +120,11 @@ int wfx_cut(Wave *w, int a, int b) {
        unsigned newSize = w->size-(b-a);
        float *temp = (float *) malloc(newSize * sizeof(float));
        if (temp == NULL) {
-               gLog("[wfx] unable to allocate memory for cutting\n");
+               gu_log("[wfx] unable to allocate memory for cutting\n");
                return 0;
        }
 
-       gLog("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2);
+       gu_log("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2);
 
        for (int i=0, k=0; i<w->size; i++) {
                if (i < a || i >= b) {                         // left margin always included, in order to keep
@@ -143,16 +140,17 @@ int wfx_cut(Wave *w, int a, int b) {
        w->frames(w->frames() - b - a);
        w->isEdited = true;
 
-       gLog("[wfx] cutting done\n");
+       gu_log("[wfx] cutting done\n");
 
        return 1;
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int wfx_trim(Wave *w, int a, int b) {
+int wfx_trim(Wave *w, int a, int b)
+{
        a = a * 2;
        b = b * 2;
 
@@ -162,11 +160,11 @@ int wfx_trim(Wave *w, int a, int b) {
        int newSize = b - a;
        float *temp = (float *) malloc(newSize * sizeof(float));
        if (temp == NULL) {
-               gLog("[wfx] unable to allocate memory for trimming\n");
+               gu_log("[wfx] unable to allocate memory for trimming\n");
                return 0;
        }
 
-       gLog("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a);
+       gu_log("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a);
 
        for (int i=a, k=0; i<b; i++, k++)
                temp[k] = w->data[i];
@@ -182,11 +180,11 @@ int wfx_trim(Wave *w, int a, int b) {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void wfx_fade(Wave *w, int a, int b, int type) {
 
+void wfx_fade(Wave *w, int a, int b, int type)
+{
        float m = type == 0 ? 0.0f : 1.0f;
        float d = 1.0f/(float)(b-a);
        if (type == 1)
@@ -200,14 +198,16 @@ void wfx_fade(Wave *w, int a, int b, int type) {
                w->data[i+1] *= m;
                m += d;
        }
-}
 
+  w->isEdited = true;
+}
 
-/* ------------------------------------------------------------------ */
 
+/* -------------------------------------------------------------------------- */
 
-void wfx_smooth(Wave *w, int a, int b) {
 
+void wfx_smooth(Wave *w, int a, int b)
+{
        int d = 32;  // 64 if stereo data
 
        /* do nothing if fade edges (both of 32 samples) are > than selected
@@ -215,7 +215,7 @@ void wfx_smooth(Wave *w, int a, int b) {
         * values. */
 
        if (d*2 > (b-a)*2) {
-               gLog("[WFX] selection is too small, nothing to do\n");
+               gu_log("[WFX] selection is too small, nothing to do\n");
                return;
        }
 
index 491b1af70fd761f7af602f17ebd61a24b13f0649..7eae643133cffbdd003bd77ecfa4c2a9a10d449b 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * waveFx
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef WAVEFX_H
index ea4e01b138c3397fd61825f86b7a50267f4d7b52..c1fa9ba88b1cf88b06ce70a602417d87550800a4 100644 (file)
 
 
 #include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_editor.h"
 #include "../gui/elems/ge_keyboard.h"
-#include "../gui/elems/ge_channel.h"
-#include "../utils/gui_utils.h"
+#include "../gui/elems/ge_waveTools.h"
+#include "../gui/elems/ge_waveform.h"
+#include "../gui/elems/channel.h"
+#include "../utils/gui.h"
 #include "../core/mixerHandler.h"
 #include "../core/mixer.h"
 #include "../core/pluginHost.h"
 #include "../core/conf.h"
+#include "../core/wave.h"
 #include "../core/channel.h"
 #include "../core/sampleChannel.h"
 #include "../core/midiChannel.h"
-#include "glue.h"
+#include "main.h"
 #include "channel.h"
 
 
-extern gdMainWindow *mainWin;
+extern gdMainWindow *G_MainWin;
 extern Conf          G_Conf;
+extern Recorder                         G_Recorder;
 extern Mixer                    G_Mixer;
 #ifdef WITH_VST
 extern PluginHost G_PluginHost;
@@ -54,17 +59,25 @@ extern PluginHost G_PluginHost;
 using std::string;
 
 
-int glue_loadChannel(SampleChannel *ch, const char *fname)
+static bool __soloSession__ = false;
+
+
+int glue_loadChannel(SampleChannel *ch, const string &fname)
 {
+  /* Always stop a channel before loading a new sample in it. This will prevent
+  issues if tracker is outside the boundaries of the new sample -> segfault. */
+
+  ch->hardStop(0);
+
        /* save the patch and take the last browser's dir in order to re-use it
         * the next time */
 
-       G_Conf.samplePath = gDirname(fname);
+       G_Conf.samplePath = gu_dirname(fname);
 
-       int result = ch->load(fname, G_Conf.samplerate, G_Conf.rsmpQuality);
+       int result = ch->load(fname.c_str(), G_Conf.samplerate, G_Conf.rsmpQuality);
 
        if (result == SAMPLE_LOADED_OK)
-               mainWin->keyboard->updateChannel(ch->guiChannel);
+               G_MainWin->keyboard->updateChannel(ch->guiChannel);
 
        return result;
 }
@@ -75,10 +88,9 @@ int glue_loadChannel(SampleChannel *ch, const char *fname)
 
 Channel *glue_addChannel(int column, int type)
 {
-       Channel *ch    = G_Mixer.addChannel(type);
-       gChannel *gch  = mainWin->keyboard->addChannel(column, ch);
-       ch->guiChannel = gch;
-       glue_setChanVol(ch, 1.0, false); // false = not from gui click
+       Channel *ch     = G_Mixer.addChannel(type);
+       geChannel *gch  = G_MainWin->keyboard->addChannel(column, ch);
+       ch->guiChannel  = gch;
        return ch;
 }
 
@@ -88,12 +100,12 @@ Channel *glue_addChannel(int column, int type)
 
 void glue_deleteChannel(Channel *ch)
 {
-       recorder::clearChan(ch->index);
+       G_Recorder.clearChan(ch->index);
 #ifdef WITH_VST
        G_PluginHost.freeStack(PluginHost::CHANNEL, &G_Mixer.mutex_plugins, ch);
 #endif
        Fl::lock();
-       mainWin->keyboard->deleteChannel(ch->guiChannel);
+       G_MainWin->keyboard->deleteChannel(ch->guiChannel);
        Fl::unlock();
        G_Mixer.deleteChannel(ch);
        gu_closeAllSubwindows();
@@ -106,10 +118,13 @@ void glue_deleteChannel(Channel *ch)
 void glue_freeChannel(Channel *ch)
 {
 #ifdef WITH_VST
+
        G_PluginHost.freeStack(PluginHost::CHANNEL, &G_Mixer.mutex_plugins, ch);
+  ch->guiChannel->fx->full = false;
+
 #endif
-       mainWin->keyboard->freeChannel(ch->guiChannel);
-       recorder::clearChan(ch->index);
+       G_MainWin->keyboard->freeChannel(ch->guiChannel);
+       G_Recorder.clearChan(ch->index);
        ch->empty();
 }
 
@@ -117,14 +132,349 @@ void glue_freeChannel(Channel *ch)
 /* -------------------------------------------------------------------------- */
 
 
+void glue_toggleArm(Channel *ch, bool gui)
+{
+       ch->armed = !ch->armed;
+       if (!gui)
+               ch->guiChannel->arm->value(ch->armed);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 int glue_cloneChannel(Channel *src)
 {
        Channel *ch    = G_Mixer.addChannel(src->type);
-       gChannel *gch  = mainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch);
+       geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch);
 
        ch->guiChannel = gch;
        ch->copy(src, &G_Mixer.mutex_plugins);
 
-       mainWin->keyboard->updateChannel(ch->guiChannel);
+       G_MainWin->keyboard->updateChannel(ch->guiChannel);
        return true;
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setChanVol(Channel *ch, float v, bool gui)
+{
+       ch->volume = v;
+
+       /* also update wave editor if it's shown */
+
+       gdEditor *editor = (gdEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR);
+       if (editor) {
+               glue_setVolEditor(editor, (SampleChannel*) ch, v, false);
+               Fl::lock();
+               editor->volume->value(v);
+               Fl::unlock();
+       }
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->vol->value(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setPitch(gdEditor *win, SampleChannel *ch, float val, bool numeric)
+{
+       if (numeric) {
+               if (val <= 0.0f)
+                       val = 0.1000f;
+               if (val > 4.0f)
+                       val = 4.0000f;
+               if (win)
+                       win->pitch->value(val);
+       }
+
+       ch->setPitch(val);
+
+       if (win) {
+               char buf[16];
+               sprintf(buf, "%.4f", val);
+               Fl::lock();
+               win->pitchNum->value(buf);
+               win->pitchNum->redraw();
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setPanning(gdEditor *win, SampleChannel *ch, float val)
+{
+       if (val < 1.0f) {
+               ch->panLeft = 1.0f;
+               ch->panRight= 0.0f + val;
+
+               char buf[8];
+               sprintf(buf, "%d L", (int) std::abs((ch->panRight * 100.0f) - 100));
+               win->panNum->value(buf);
+       }
+       else if (val == 1.0f) {
+               ch->panLeft = 1.0f;
+               ch->panRight= 1.0f;
+         win->panNum->value("C");
+       }
+       else {
+               ch->panLeft = 2.0f - val;
+               ch->panRight= 1.0f;
+
+               char buf[8];
+               sprintf(buf, "%d R", (int) std::abs((ch->panLeft * 100.0f) - 100));
+               win->panNum->value(buf);
+       }
+       win->panNum->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setMute(Channel *ch, bool gui)
+{
+       if (G_Recorder.active && G_Recorder.canRec(ch)) {
+               if (!ch->mute)
+                       G_Recorder.startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame);
+               else
+                G_Recorder.stopOverdub(G_Mixer.actualFrame);
+       }
+
+       ch->mute ? ch->unsetMute(false) : ch->setMute(false);
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->mute->value(ch->mute);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setSoloOn(Channel *ch, bool gui)
+{
+       /* if there's no solo session, store mute configuration of all chans
+        * and start the session */
+
+       if (!__soloSession__) {
+               for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+                       Channel *och = G_Mixer.channels.at(i);
+                       och->mute_s  = och->mute;
+               }
+               __soloSession__ = true;
+       }
+
+       ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
+
+       /* mute all other channels and unmute this (if muted) */
+
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+               Channel *och = G_Mixer.channels.at(i);
+               if (!och->solo && !och->mute) {
+                       och->setMute(false);
+                       Fl::lock();
+                       och->guiChannel->mute->value(true);
+                       Fl::unlock();
+               }
+       }
+
+       if (ch->mute) {
+               ch->unsetMute(false);
+               Fl::lock();
+               ch->guiChannel->mute->value(false);
+               Fl::unlock();
+       }
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->solo->value(1);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setSoloOff(Channel *ch, bool gui)
+{
+       /* if this is uniqueSolo, stop solo session and restore mute status,
+        * else mute this */
+
+       if (mh_uniqueSolo(ch)) {
+               __soloSession__ = false;
+               for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+                       Channel *och = G_Mixer.channels.at(i);
+                       if (och->mute_s) {
+                               och->setMute(false);
+                               Fl::lock();
+                               och->guiChannel->mute->value(true);
+                               Fl::unlock();
+                       }
+                       else {
+                               och->unsetMute(false);
+                               Fl::lock();
+                               och->guiChannel->mute->value(false);
+                               Fl::unlock();
+                       }
+                       och->mute_s = false;
+               }
+       }
+       else {
+               ch->setMute(false);
+               Fl::lock();
+               ch->guiChannel->mute->value(true);
+               Fl::unlock();
+       }
+
+       ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
+
+       if (!gui) {
+               Fl::lock();
+               ch->guiChannel->solo->value(0);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e,
+       bool recalc, bool check)
+{
+       if (check) {
+               if (e > ch->wave->size)
+                       e = ch->wave->size;
+               if (b < 0)
+                       b = 0;
+               if (b > ch->wave->size)
+                       b = ch->wave->size-2;
+               if (b >= ch->end)
+                       b = ch->begin;
+               if (e <= ch->begin)
+                       e = ch->end;
+       }
+
+       /* continue only if new values != old values */
+
+       if (b == ch->begin && e == ch->end)
+               return;
+
+       /* print mono values */
+
+       char tmp[16];
+       sprintf(tmp, "%d", b/2);
+       win->chanStart->value(tmp);
+
+       tmp[0] = '\0';
+       sprintf(tmp, "%d", e/2);
+       win->chanEnd->value(tmp);
+
+       ch->setBegin(b);
+       ch->setEnd(e);
+
+       /* Recalc is not needed when the user drags the bars directly over the
+       waveform */
+
+       if (recalc) {
+               win->waveTools->waveform->recalcPoints();
+               win->waveTools->waveform->redraw();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric)
+{
+       if (numeric) {
+               if (val > 20.0f)
+                       val = 20.0f;
+               else if (val < 0.0f)
+                       val = 0.0f;
+
+         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
+
+               ch->boost = linear;
+
+               char buf[10];
+               sprintf(buf, "%.2f", val);
+               win->boostNum->value(buf);
+               win->boostNum->redraw();
+
+               win->boost->value(linear);
+               win->boost->redraw();       /// inutile
+       }
+       else {
+               ch->boost = val;
+               char buf[10];
+               sprintf(buf, "%.2f", 20*log10(val));
+               win->boostNum->value(buf);
+               win->boostNum->redraw();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val,
+       bool numeric)
+{
+       if (numeric) {
+               if (val > 0.0f)
+                       val = 0.0f;
+               else if (val < -60.0f)
+                       val = -INFINITY;
+
+         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
+
+               ch->volume = linear;
+
+               win->volume->value(linear);
+               win->volume->redraw();
+
+               char buf[10];
+               if (val > -INFINITY)
+                       sprintf(buf, "%.2f", val);
+               else
+                       sprintf(buf, "-inf");
+               win->volumeNum->value(buf);
+               win->volumeNum->redraw();
+
+               ch->guiChannel->vol->value(linear);
+               ch->guiChannel->vol->redraw();
+       }
+       else {
+               ch->volume = val;
+
+               float dbVal = 20 * log10(val);
+               char buf[10];
+               if (dbVal > -INFINITY)
+                       sprintf(buf, "%.2f", dbVal);
+               else
+                       sprintf(buf, "-inf");
+
+               win->volumeNum->value(buf);
+               win->volumeNum->redraw();
+
+               ch->guiChannel->vol->value(val);
+               ch->guiChannel->vol->redraw();
+       }
+}
index 2da2bf1a7f9ad85c8c1a41dbb39a26daca639e68..25523e09630e2f70ebda3e2ab0c6d5e4c2b145ff 100644 (file)
 #define GLUE_CHANNEL_H
 
 
-#include "../core/patch.h"
-
-
-using std::string;
+#include <string>
 
 
 /* addChannel
@@ -46,7 +43,7 @@ class Channel *glue_addChannel(int column, int type);
 /* loadChannel
  * fill an existing channel with a wave. */
 
-int glue_loadChannel(class SampleChannel *ch, const char *fname);
+int glue_loadChannel(class SampleChannel *ch, const std::string &fname);
 
 /* deleteChannel
  * Remove a channel from Mixer. */
@@ -60,8 +57,41 @@ void glue_freeChannel(class Channel *ch);
 
 /* cloneChannel
  * Make an exact copy of Channel *ch. */
+
 int glue_cloneChannel(class Channel *ch);
 
+/* toggle/set*
+ * Toggle or set several channel properties. If gui == true the signal comes
+ * from a manual interaction on the GUI, otherwise it's a MIDI/Jack/external
+ * signal. */
+
+void glue_toggleArm(class Channel *ch, bool gui=true);
+void glue_setChanVol(class Channel *ch, float v, bool gui=true);
+void glue_setMute(class Channel *ch, bool gui=true);
+void glue_setSoloOn (class Channel *ch, bool gui=true);
+void glue_setSoloOff(class Channel *ch, bool gui=true);
+
+void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val,
+  bool numeric);
+
+void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val);
+
+/* setBeginEndChannel
+ * sets start/end points in the sample editor. Recalc=false: don't recalc
+ * internal position. check=true: check the points' consistency */
+
+void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch,
+  int b, int e, bool recalc=false, bool check=true);
+
+void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val,
+  bool numeric);
+
+/* setVolEditor
+ * handles the volume inside the SAMPLE EDITOR (not the main gui). The
+ * numeric flag tells if we want to handle the dial or the numeric input
+ * field. */
+
+void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val,
+  bool numeric);
 
 #endif
diff --git a/src/glue/glue.cpp b/src/glue/glue.cpp
deleted file mode 100644 (file)
index ff1670c..0000000
+++ /dev/null
@@ -1,972 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * glue
- * Intermediate layer GUI <-> CORE.
- *
- * How to know if you need another glue_ function? Ask yourself if the
- * new action will ever be called via MIDI or keyboard/mouse. If yes,
- * put it here.
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../gui/elems/ge_waveform.h"
-#include "../gui/elems/ge_mixed.h"
-#include "../gui/elems/ge_channel.h"
-#include "../gui/elems/ge_sampleChannel.h"
-#include "../gui/elems/ge_waveTools.h"
-#include "../gui/elems/ge_keyboard.h"
-#include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/dialogs/gd_editor.h"
-#include "../gui/dialogs/gd_warnings.h"
-#include "../utils/gui_utils.h"
-#include "../utils/utils.h"
-#include "../utils/log.h"
-#include "../core/mixerHandler.h"
-#include "../core/mixer.h"
-#include "../core/recorder.h"
-#include "../core/wave.h"
-#include "../core/pluginHost.h"
-#include "../core/channel.h"
-#include "../core/sampleChannel.h"
-#include "../core/midiChannel.h"
-#include "../core/kernelMidi.h"
-#include "../core/patch_DEPR_.h"
-#include "../core/conf.h"
-#include "glue.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer                    G_Mixer;
-extern Patch_DEPR_   G_Patch_DEPR_;
-extern Conf                             G_Conf;
-extern bool                             G_audio_status;
-#ifdef WITH_VST
-extern PluginHost    G_PluginHost;
-#endif
-
-
-static bool __soloSession__ = false;
-
-
-void glue_setBpm(const char *v1, const char *v2)
-{
-       char  buf[6];
-       float value = atof(v1) + (atof(v2)/10);
-       if (value < 20.0f)      {
-               value = 20.0f;
-               sprintf(buf, "20.0");
-       }
-       else
-               sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2);
-
-       /* a value such as atof("120.1") will never be 120.1 but 120.0999999,
-        * because of the rounding error. So we pass the real "wrong" value to
-        * G_Mixer and we show the nice looking (but fake) one to the GUI. */
-
-       float old_bpm = G_Mixer.bpm;
-       G_Mixer.bpm = value;
-       G_Mixer.updateFrameBars();
-
-       /* inform recorder and actionEditor of the change */
-
-       recorder::updateBpm(old_bpm, value, G_Mixer.quanto);
-       gu_refreshActionEditor();
-
-       mainWin->timing->setBpm(buf);
-       gLog("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBeats(int beats, int bars, bool expand)
-{
-       /* temp vars to store old data (they are necessary) */
-
-       int      oldvalue = G_Mixer.beats;
-       unsigned oldfpb         = G_Mixer.totalFrames;
-
-       if (beats > MAX_BEATS)
-               G_Mixer.beats = MAX_BEATS;
-       else if (beats < 1)
-               G_Mixer.beats = 1;
-       else
-               G_Mixer.beats = beats;
-
-       /* update bars - bars cannot be greate than beats and must be a sub
-        * multiple of beats. If not, approximation to the nearest (and greater)
-        * value available. */
-
-       if (bars > G_Mixer.beats)
-               G_Mixer.bars = G_Mixer.beats;
-       else if (bars <= 0)
-               G_Mixer.bars = 1;
-       else if (beats % bars != 0) {
-               G_Mixer.bars = bars + (beats % bars);
-               if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it)
-                       G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars);
-       }
-       else
-               G_Mixer.bars = bars;
-
-       G_Mixer.updateFrameBars();
-
-       /* update recorded actions */
-
-       if (expand) {
-               if (G_Mixer.beats > oldvalue)
-                       recorder::expand(oldfpb, G_Mixer.totalFrames);
-               //else if (G_Mixer.beats < oldvalue)
-               //      recorder::shrink(G_Mixer.totalFrames);
-       }
-
-       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
-       gu_refreshActionEditor();  // in case the action editor is open
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopSeq(bool gui)
-{
-       G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startSeq(bool gui)
-{
-       G_Mixer.running = true;
-
-       if (gui) {
-#ifdef __linux__
-               kernelAudio::jackStart();
-#endif
-       }
-
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
-               kernelMidi::send(MIDI_START, -1, -1);
-               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
-       }
-
-       if (gui) Fl::lock();
-       mainWin->controller->updatePlay(1);
-       if (gui) Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopSeq(bool gui) {
-
-       mh_stopSequencer();
-
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
-               kernelMidi::send(MIDI_STOP, -1, -1);
-
-#ifdef __linux__
-       if (gui)
-               kernelAudio::jackStop();
-#endif
-
-       /* what to do if we stop the sequencer and some action recs are active?
-        * Deactivate the button and delete any 'rec on' status */
-
-       if (recorder::active) {
-               recorder::active = false;
-               if (gui) Fl::lock();
-               mainWin->controller->updateRecAction(0);
-               if (gui) Fl::unlock();
-       }
-
-       /* if input recs are active (who knows why) we must deactivate them.
-        * One might stop the sequencer while an input rec is running. */
-
-       if (G_Mixer.chanInput != NULL) {
-               mh_stopInputRec();
-               if (gui) Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               if (gui) Fl::unlock();
-       }
-
-       if (gui) Fl::lock();
-       mainWin->controller->updatePlay(0);
-       if (gui) Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_rewindSeq() {
-       mh_rewindSequencer();
-       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
-               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopActionRec() {
-       recorder::active ? glue_stopActionRec() : glue_startActionRec();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startActionRec() {
-       if (G_audio_status == false)
-               return;
-       if (!G_Mixer.running)
-               glue_startSeq();                // start the sequencer for convenience
-       recorder::active = true;
-
-       Fl::lock();
-       mainWin->controller->updateRecAction(1);
-       Fl::unlock();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopActionRec() {
-
-       /* stop the recorder and sort new actions */
-
-       recorder::active = false;
-       recorder::sortActions();
-
-       for (unsigned i=0; i<G_Mixer.channels.size(); i++)
-               if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) {
-                       SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
-                       if (ch->hasActions)
-                               ch->readActions = true;
-                       else
-                               ch->readActions = false;
-                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel);
-               }
-
-       Fl::lock();
-       mainWin->controller->updateRecAction(0);
-       Fl::unlock();
-
-       /* in case acton editor is on, refresh it */
-
-       gu_refreshActionEditor();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopReadingRecs(SampleChannel *ch, bool gui) {
-       if (ch->readActions)
-               glue_stopReadingRecs(ch, gui);
-       else
-               glue_startReadingRecs(ch, gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startReadingRecs(SampleChannel *ch, bool gui) {
-       if (G_Conf.treatRecsAsLoops)
-               ch->recStatus = REC_WAITING;
-       else
-               ch->setReadActions(true, G_Conf.recsStopOnChanHalt);
-       if (!gui) {
-               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
-               if (gch->readActions) { // if button exists
-                       Fl::lock();
-                       gch->readActions->value(1);
-                       Fl::unlock();
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_stopReadingRecs(SampleChannel *ch, bool gui) {
-
-       /* if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put
-        * the channel in REC_ENDING status */
-
-       if (G_Conf.treatRecsAsLoops)
-               ch->recStatus = REC_ENDING;
-       else
-               ch->setReadActions(false, G_Conf.recsStopOnChanHalt);
-       if (!gui) {
-               gSampleChannel *gch = (gSampleChannel*)ch->guiChannel;
-               if (gch->readActions) {  // if button exists
-                       Fl::lock();
-                       gch->readActions->value(0);
-                       Fl::unlock();
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_quantize(int val) {
-       G_Mixer.quantize = val;
-       G_Mixer.updateQuanto();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setChanVol(Channel *ch, float v, bool gui) {
-
-       ch->volume = v;
-
-       /* also update wave editor if it's shown */
-
-       gdEditor *editor = (gdEditor*) gu_getSubwindow(mainWin, WID_SAMPLE_EDITOR);
-       if (editor) {
-               glue_setVolEditor(editor, (SampleChannel*) ch, v, false);
-               Fl::lock();
-               editor->volume->value(v);
-               Fl::unlock();
-       }
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->vol->value(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setOutVol(float v, bool gui) {
-       G_Mixer.outVol = v;
-       if (!gui) {
-               Fl::lock();
-               mainWin->inOut->setOutVol(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setInVol(float v, bool gui)
-{
-       G_Mixer.inVol = v;
-       if (!gui) {
-               Fl::lock();
-               mainWin->inOut->setInVol(v);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_clearAllSamples()
-{
-       G_Mixer.running = false;
-       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-               G_Mixer.channels.at(i)->empty();
-               G_Mixer.channels.at(i)->guiChannel->reset();
-       }
-       recorder::init();
-       return;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_clearAllRecs()
-{
-       recorder::init();
-       gu_updateControls();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_resetToInitState(bool resetGui, bool createColumns)
-{
-       G_Patch_DEPR_.setDefault();
-       G_Mixer.close();
-       G_Mixer.init();
-       recorder::init();
-#ifdef WITH_VST
-       G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins);
-#endif
-
-       mainWin->keyboard->clear();
-       if (createColumns)
-               mainWin->keyboard->init();
-
-       if (resetGui)
-               gu_updateControls();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopMetronome(bool gui)
-{
-       G_Mixer.metronome = !G_Mixer.metronome;
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateMetronome(G_Mixer.metronome);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, bool recalc, bool check)
-{
-       if (check) {
-               if (e > ch->wave->size)
-                       e = ch->wave->size;
-               if (b < 0)
-                       b = 0;
-               if (b > ch->wave->size)
-                       b = ch->wave->size-2;
-               if (b >= ch->end)
-                       b = ch->begin;
-               if (e <= ch->begin)
-                       e = ch->end;
-       }
-
-       /* continue only if new values != old values */
-
-       if (b == ch->begin && e == ch->end)
-               return;
-
-       /* print mono values */
-
-       char tmp[16];
-       sprintf(tmp, "%d", b/2);
-       win->chanStart->value(tmp);
-
-       tmp[0] = '\0';
-       sprintf(tmp, "%d", e/2);
-       win->chanEnd->value(tmp);
-
-       ch->setBegin(b);
-       ch->setEnd(e);
-
-       /* recalc is not needed when the user drags the bars directly over the waveform */
-
-       if (recalc) {
-               win->waveTools->waveform->recalcPoints();       // importante, altrimenti non si vedono
-               win->waveTools->waveform->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val > 20.0f)
-                       val = 20.0f;
-               else if (val < 0.0f)
-                       val = 0.0f;
-
-         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
-
-               ch->boost = linear;
-
-               char buf[10];
-               sprintf(buf, "%.2f", val);
-               win->boostNum->value(buf);
-               win->boostNum->redraw();
-
-               win->boost->value(linear);
-               win->boost->redraw();       /// inutile
-       }
-       else {
-               ch->boost = val;
-               char buf[10];
-               sprintf(buf, "%.2f", 20*log10(val));
-               win->boostNum->value(buf);
-               win->boostNum->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val > 0.0f)
-                       val = 0.0f;
-               else if (val < -60.0f)
-                       val = -INFINITY;
-
-         float linear = pow(10, (val / 20)); // linear = 10^(dB/20)
-
-               ch->volume = linear;
-
-               win->volume->value(linear);
-               win->volume->redraw();
-
-               char buf[10];
-               if (val > -INFINITY)
-                       sprintf(buf, "%.2f", val);
-               else
-                       sprintf(buf, "-inf");
-               win->volumeNum->value(buf);
-               win->volumeNum->redraw();
-
-               ch->guiChannel->vol->value(linear);
-               ch->guiChannel->vol->redraw();
-       }
-       else {
-               ch->volume = val;
-
-               float dbVal = 20 * log10(val);
-               char buf[10];
-               if (dbVal > -INFINITY)
-                       sprintf(buf, "%.2f", dbVal);
-               else
-                       sprintf(buf, "-inf");
-
-               win->volumeNum->value(buf);
-               win->volumeNum->redraw();
-
-               ch->guiChannel->vol->value(val);
-               ch->guiChannel->vol->redraw();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setMute(Channel *ch, bool gui)
-{
-       if (recorder::active && recorder::canRec(ch)) {
-               if (!ch->mute)
-                       recorder::startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame);
-               else
-                recorder::stopOverdub(G_Mixer.actualFrame);
-       }
-
-       ch->mute ? ch->unsetMute(false) : ch->setMute(false);
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->mute->value(ch->mute);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setSoloOn(Channel *ch, bool gui)
-{
-       /* if there's no solo session, store mute configuration of all chans
-        * and start the session */
-
-       if (!__soloSession__) {
-               for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-                       Channel *och = G_Mixer.channels.at(i);
-                       och->mute_s  = och->mute;
-               }
-               __soloSession__ = true;
-       }
-
-       ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       /* mute all other channels and unmute this (if muted) */
-
-       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-               Channel *och = G_Mixer.channels.at(i);
-               if (!och->solo && !och->mute) {
-                       och->setMute(false);
-                       Fl::lock();
-                       och->guiChannel->mute->value(true);
-                       Fl::unlock();
-               }
-       }
-
-       if (ch->mute) {
-               ch->unsetMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(false);
-               Fl::unlock();
-       }
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->solo->value(1);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setSoloOff(Channel *ch, bool gui)
-{
-       /* if this is uniqueSolo, stop solo session and restore mute status,
-        * else mute this */
-
-       if (mh_uniqueSolo(ch)) {
-               __soloSession__ = false;
-               for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-                       Channel *och = G_Mixer.channels.at(i);
-                       if (och->mute_s) {
-                               och->setMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(true);
-                               Fl::unlock();
-                       }
-                       else {
-                               och->unsetMute(false);
-                               Fl::lock();
-                               och->guiChannel->mute->value(false);
-                               Fl::unlock();
-                       }
-                       och->mute_s = false;
-               }
-       }
-       else {
-               ch->setMute(false);
-               Fl::lock();
-               ch->guiChannel->mute->value(true);
-               Fl::unlock();
-       }
-
-       ch->solo = !ch->solo;
-       ch->sendMidiLsolo();
-
-       if (!gui) {
-               Fl::lock();
-               ch->guiChannel->solo->value(0);
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val)
-{
-       if (val < 1.0f) {
-               ch->panLeft = 1.0f;
-               ch->panRight= 0.0f + val;
-
-               char buf[8];
-               sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100));
-               win->panNum->value(buf);
-       }
-       else if (val == 1.0f) {
-               ch->panLeft = 1.0f;
-               ch->panRight= 1.0f;
-         win->panNum->value("C");
-       }
-       else {
-               ch->panLeft = 2.0f - val;
-               ch->panRight= 1.0f;
-
-               char buf[8];
-               sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100));
-               win->panNum->value(buf);
-       }
-       win->panNum->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_startStopInputRec(bool gui, bool alert)
-{
-       if (G_Mixer.chanInput == NULL) {
-               if (!glue_startInputRec(gui)) {
-                       if (alert) gdAlert("No channels available for recording.");
-                       else       gLog("[glue] no channels available for recording\n");
-               }
-       }
-       else
-               glue_stopInputRec(gui);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_startInputRec(bool gui)
-{
-       if (G_audio_status == false)
-               return -1;
-
-       SampleChannel *ch = mh_startInputRec();
-       if (ch == NULL) {                  // no chans available
-               Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               Fl::unlock();
-               return 0;
-       }
-
-       if (!G_Mixer.running) {
-               glue_startSeq();
-               Fl::lock();
-               mainWin->controller->updatePlay(1);
-               Fl::unlock();
-       }
-
-       glue_setChanVol(ch, 1.0f, false); // false = not from gui click
-
-       ch->guiChannel->mainButton->label(ch->wave->name.c_str());
-
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateRecInput(1);
-               Fl::unlock();
-       }
-
-       return 1;
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int glue_stopInputRec(bool gui)
-{
-       SampleChannel *ch = mh_stopInputRec();
-
-       if (ch->mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT))
-               ch->start(0, true, G_Mixer.quantize, G_Mixer.running);  // on frame 0: user-generated event
-
-       if (!gui) {
-               Fl::lock();
-               mainWin->controller->updateRecInput(0);
-               Fl::unlock();
-       }
-
-       return 1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(Channel *ch, bool ctrl, bool shift)
-{
-       if (ch->type == CHANNEL_SAMPLE)
-               glue_keyPress((SampleChannel*)ch, ctrl, shift);
-       else
-               glue_keyPress((MidiChannel*)ch, ctrl, shift);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyRelease(Channel *ch, bool ctrl, bool shift)
-{
-       if (ch->type == CHANNEL_SAMPLE)
-               glue_keyRelease((SampleChannel*)ch, ctrl, shift);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift)
-{
-       if (ctrl)
-               glue_setMute(ch);
-       else
-       if (shift)
-               ch->kill(0);        // on frame 0: user-generated event
-       else
-               ch->start(0, true, G_Mixer.quantize, G_Mixer.running); // on frame 0: user-generated event
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift)
-{
-       /* case CTRL */
-
-       if (ctrl)
-               glue_setMute(ch);
-
-       /* case SHIFT
-        *
-        * action recording on:
-        *              if seq is playing, rec a killchan
-        * action recording off:
-        *              if chan has recorded events:
-        *              |        if seq is playing OR channel 'c' is stopped, de/activate recs
-        *              |        else kill chan
-        *              else kill chan */
-
-       else
-       if (shift) {
-               if (recorder::active) {
-                       if (G_Mixer.running) {
-                               ch->kill(0); // on frame 0: user-generated event
-                               if (recorder::canRec(ch) && !(ch->mode & LOOP_ANY))   // don't record killChan actions for LOOP channels
-                                       recorder::rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame);
-                       }
-               }
-               else {
-                       if (ch->hasActions) {
-                               if (G_Mixer.running || ch->status == STATUS_OFF)
-                                       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
-                               else
-                                       ch->kill(0);  // on frame 0: user-generated event
-                       }
-                       else
-                               ch->kill(0);    // on frame 0: user-generated event
-               }
-       }
-
-       /* case no modifier */
-
-       else {
-
-               /* record now if the quantizer is off, otherwise let mixer to handle it
-                * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are
-                * meaningless for loop modes */
-
-               if (G_Mixer.quantize == 0 &&
-                   recorder::canRec(ch)  &&
-             !(ch->mode & LOOP_ANY))
-               {
-                       if (ch->mode == SINGLE_PRESS)
-                               recorder::startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame);
-                       else
-                               recorder::rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame);
-               }
-
-               ch->start(0, true, G_Mixer.quantize, G_Mixer.running); // on frame 0: user-generated event
-       }
-
-       /* the GUI update is done by gui_refresh() */
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift)
-{
-       if (!ctrl && !shift) {
-               ch->stop();
-
-               /* record a key release only if channel is single_press. For any
-                * other mode the KEY REL is meaningless. */
-
-               if (ch->mode == SINGLE_PRESS && recorder::canRec(ch))
-                       recorder::stopOverdub(G_Mixer.actualFrame);
-       }
-
-       /* the GUI update is done by gui_refresh() */
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void glue_setPitch(class gdEditor *win, SampleChannel *ch, float val, bool numeric)
-{
-       if (numeric) {
-               if (val <= 0.0f)
-                       val = 0.1000f;
-               if (val > 4.0f)
-                       val = 4.0000f;
-               if (win)
-                       win->pitch->value(val);
-       }
-
-       ch->setPitch(val);
-
-       if (win) {
-               char buf[16];
-               sprintf(buf, "%.4f", val);
-               Fl::lock();
-               win->pitchNum->value(buf);
-               win->pitchNum->redraw();
-               Fl::unlock();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-/* never expand or shrink recordings (last param of setBeats = false):
- * this is live manipulation */
-
-void glue_beatsMultiply()
-{
-       glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false);
-}
-
-void glue_beatsDivide()
-{
-       glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false);
-}
diff --git a/src/glue/glue.h b/src/glue/glue.h
deleted file mode 100644 (file)
index ef7076f..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * glue
- * Intermediate layer GUI <-> CORE.
- *
- * How to know if you need another glue_ function? Ask yourself if the
- * new action will ever be called via MIDI or keyboard/mouse. If yes,
- * put it here.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GLUE_H
-#define GLUE_H
-
-
-/* keyPress / keyRelease
- * handle the key pressure, either via mouse/keyboard or MIDI. If gui
- * is true it means that the event comes from the main window (mouse,
- * keyb or MIDI), otherwise the event comes from the action recorder. */
-
-void glue_keyPress  (class Channel       *ch, bool ctrl=0, bool shift=0);
-void glue_keyPress  (class SampleChannel *ch, bool ctrl=0, bool shift=0);
-void glue_keyPress  (class MidiChannel   *ch, bool ctrl=0, bool shift=0);
-void glue_keyRelease(class Channel       *ch, bool ctrl=0, bool shift=0);
-void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0);
-
-void glue_setBpm(const char *v1, const char *v2);
-void glue_setBeats(int beats, int bars, bool expand);
-
-/* start, stop, rewind sequencer
- * if gui == true the signal comes from an internal interaction on the
- * GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_startStopSeq(bool gui=true);
-void glue_startSeq    (bool gui=true);
-void glue_stopSeq     (bool gui=true);
-void glue_rewindSeq   ();
-
-/* start/stopActionRec
- * handle the action recording. */
-
-void glue_startStopActionRec();
-void glue_startActionRec();
-void glue_stopActionRec();
-
-/* start/stopInputRec
- * handle the input recording (take). If gui == true the signal comes
- * from an internal interaction on the GUI, otherwise it's a
- * MIDI/Jack/external signal. Alert displays or not the popup message
- * if there are no available channels. */
-
-void glue_startStopInputRec(bool gui=true, bool alert=true);
-int  glue_startInputRec    (bool gui=true);
-int  glue_stopInputRec     (bool gui=true);
-
-/* start/stopReadingRecs
- * handle the 'R' button. If gui == true the signal comes from an
- * internal interaction on the GUI, otherwise it's a MIDI/Jack/external
- * signal. */
-
-void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true);
-void glue_startReadingRecs    (class SampleChannel *ch, bool gui=true);
-void glue_stopReadingRecs     (class SampleChannel *ch, bool gui=true);
-
-void glue_quantize(int val);
-
-void glue_setChanVol(class Channel *ch, float v, bool gui=true);
-void glue_setOutVol (float v, bool gui=true);
-void glue_setInVol  (float v, bool gui=true);
-
-void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val);
-
-void glue_clearAllSamples();
-void glue_clearAllRecs();
-
-/* resetToInitState
- * reset Giada to init state. If resetGui also refresh all widgets. If
- * createColumns also build initial empty columns. */
-
-void glue_resetToInitState(bool resetGui=true, bool createColumns=true);
-
-void glue_startStopMetronome(bool gui=true);
-
-/* setBeginEndChannel
- * sets start/end points in the sample editor.
- * Recalc=false: don't recalc internal position
- * check=true: check the points' consistency */
-
-/** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, int b, int e,
-                                                                                                                bool recalc=false, bool check=true);
-
-/** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-/* setVolEditor
- * handles the volume inside the SAMPLE EDITOR (not the main gui). The
- * numeric flag tells if we want to handle the dial or the numeric input
- * field. */
-
- /** FIXME - nobody will call this via MIDI/keyb/mouse! */
-void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric);
-
-/* mute
- * set mute on or off. If gui == true the signal comes from an internal
- * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_setMute(class Channel *ch, bool gui=true);
-
-/* solo on/off
- * set solo on and off. If gui == true the signal comes from an internal
- * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
-
-void glue_setSoloOn (class Channel *ch, bool gui=true);
-void glue_setSoloOff(class Channel *ch, bool gui=true);
-
-/* beatsDivide/Multiply
- * shrinks or enlarges the number of beats by 2. */
-
-void glue_beatsMultiply();
-void glue_beatsDivide();
-
-#endif
diff --git a/src/glue/io.cpp b/src/glue/io.cpp
new file mode 100644 (file)
index 0000000..bdc932e
--- /dev/null
@@ -0,0 +1,327 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/Fl.H>
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "../gui/elems/channel.h"
+#include "../gui/elems/sampleChannel.h"
+#include "../utils/gui.h"
+#include "../utils/log.h"
+#include "../core/recorder.h"
+#include "../core/mixer.h"
+#include "../core/mixerHandler.h"
+#include "../core/wave.h"
+#include "../core/channel.h"
+#include "../core/sampleChannel.h"
+#include "../core/midiChannel.h"
+#include "main.h"
+#include "channel.h"
+#include "io.h"
+
+
+extern Recorder                         G_Recorder;
+extern bool                             G_audio_status;
+extern Mixer                    G_Mixer;
+extern gdMainWindow *G_MainWin;
+
+
+void glue_keyPress(Channel *ch, bool ctrl, bool shift)
+{
+       if (ch->type == CHANNEL_SAMPLE)
+               glue_keyPress((SampleChannel*)ch, ctrl, shift);
+       else
+               glue_keyPress((MidiChannel*)ch, ctrl, shift);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyRelease(Channel *ch, bool ctrl, bool shift)
+{
+       if (ch->type == CHANNEL_SAMPLE)
+               glue_keyRelease((SampleChannel*)ch, ctrl, shift);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift)
+{
+       if (ctrl)
+               glue_setMute(ch);
+       else
+       if (shift)
+               ch->kill(0);        // on frame 0: user-generated event
+       else
+               ch->start(0, true, G_Mixer.quantize, G_Mixer.running, false, true); // on frame 0: user-generated event
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift)
+{
+       /* case CTRL */
+
+       if (ctrl)
+               glue_setMute(ch);
+
+       /* case SHIFT
+        *
+        * action recording on:
+        *              if seq is playing, rec a killchan
+        * action recording off:
+        *              if chan has recorded events:
+        *              |        if seq is playing OR channel 'c' is stopped, de/activate recs
+        *              |        else kill chan
+        *              else kill chan */
+
+       else
+       if (shift) {
+               if (G_Recorder.active) {
+                       if (G_Mixer.running) {
+                               ch->kill(0); // on frame 0: user-generated event
+                               if (G_Recorder.canRec(ch) && !(ch->mode & LOOP_ANY))   // don't record killChan actions for LOOP channels
+                                       G_Recorder.rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame);
+                       }
+               }
+               else {
+                       if (ch->hasActions) {
+                               if (G_Mixer.running || ch->status == STATUS_OFF)
+                                       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
+                               else
+                                       ch->kill(0);  // on frame 0: user-generated event
+                       }
+                       else
+                               ch->kill(0);    // on frame 0: user-generated event
+               }
+       }
+       else {  /* case no modifier */
+
+               /* record now if the quantizer is off, otherwise let mixer to handle it
+                * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are
+                * meaningless for loop modes */
+
+               if (G_Mixer.quantize == 0  &&
+                   G_Recorder.canRec(ch)  &&
+             !(ch->mode & LOOP_ANY))
+               {
+                       if (ch->mode == SINGLE_PRESS)
+                               G_Recorder.startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame);
+                       else {
+                               G_Recorder.rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame);
+
+        /* Why return here? You record an action (as done on line 148) and then
+                               you call ch->start (line 165): Mixer, which is on another thread, reads
+        your newly recorded action if you have readActions == true, and then
+        ch->start kicks in right after it      (as done on     line 165).
+                               The result: Mixer plays the channel (due to the new action) but ch->start
+                               kills it right away (because the sample is playing). Fix: call ch->start
+                               only if you are not recording anything, i.e. let Mixer play it. */
+
+        if (ch->readActions)
+          return;
+                       }
+               }
+
+               /* This is a user-generated event, so it's on frame 0 */
+
+               ch->start(0, true, G_Mixer.quantize, G_Mixer.running, false, true);
+       }
+
+       /* the GUI update is done by gui_refresh() */
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift)
+{
+       if (ctrl || shift)
+               return;
+
+       ch->stop();
+
+       /* record a key release only if channel is single_press. For any
+        * other mode the KEY REL is meaningless. */
+
+       if (ch->mode == SINGLE_PRESS && G_Recorder.canRec(ch))
+               G_Recorder.stopOverdub(G_Mixer.actualFrame);
+
+       /* the GUI update is done by gui_refresh() */
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopActionRec(bool gui)
+{
+       G_Recorder.active ? glue_stopActionRec(gui) : glue_startActionRec(gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startActionRec(bool gui)
+{
+       if (G_audio_status == false)
+               return;
+
+       G_Recorder.active = true;
+
+       if (!G_Mixer.running)
+               glue_startSeq(false);  // update gui ayway
+
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->controller->updateRecAction(1);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopActionRec(bool gui)
+{
+       /* stop the recorder and sort new actions */
+
+       G_Recorder.active = false;
+       G_Recorder.sortActions();
+
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++)
+       {
+               if (G_Mixer.channels.at(i)->type == CHANNEL_MIDI)
+                       continue;
+               SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
+               G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)ch->guiChannel);
+               if (!ch->readActions && ch->hasActions)
+                       glue_startReadingRecs(ch, false);
+       }
+
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->controller->updateRecAction(0);
+               Fl::unlock();
+       }
+
+       gu_refreshActionEditor();  // in case it's open
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopInputRec(bool gui)
+{
+       if (G_Mixer.recording)
+               glue_stopInputRec(gui);
+       else
+       if (!glue_startInputRec(gui))
+               gdAlert("No channels armed/available for audio recording.");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_startInputRec(bool gui)
+{
+       if (G_audio_status == false)
+               return false;
+
+       if (!mh_startInputRec()) {
+         Fl::lock();
+         G_MainWin->controller->updateRecInput(0);  // set it off, anyway
+               Fl::unlock();
+               return false;
+       }
+
+       if (!G_Mixer.running)
+               glue_startSeq(false); // update gui anyway
+
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->controller->updateRecInput(1);
+               Fl::unlock();
+       }
+
+  /* Update sample name inside sample channels' main button. This is useless for
+  midi channel, but let's do it anyway. */
+
+  for (unsigned i=0; i<G_Mixer.channels.size(); i++)
+    G_Mixer.channels.at(i)->guiChannel->update();
+
+       return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int glue_stopInputRec(bool gui)
+{
+       mh_stopInputRec();
+
+       /* Start all sample channels in loop mode that were armed, i.e. that were
+       recording stuff and not yet in play. They are also started in force mode, i.e.
+  they must start playing right away at the current frame, not at the next first
+  beat. */
+
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+               if (G_Mixer.channels.at(i)->type == CHANNEL_MIDI)
+                       continue;
+               SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i);
+               if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->armed)
+                       ch->start(G_Mixer.actualFrame, true, G_Mixer.quantize, G_Mixer.running, true, true);
+       }
+
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->controller->updateRecInput(0);
+               Fl::unlock();
+       }
+
+       return 1;
+}
diff --git a/src/glue/io.h b/src/glue/io.h
new file mode 100644 (file)
index 0000000..b56160f
--- /dev/null
@@ -0,0 +1,67 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GLUE_IO_H
+#define GLUE_IO_H
+
+
+/* keyPress / keyRelease
+ * handle the key pressure, either via mouse/keyboard or MIDI. If gui
+ * is true it means that the event comes from the main window (mouse,
+ * keyb or MIDI), otherwise the event comes from the action recorder. */
+
+void glue_keyPress  (class Channel       *ch, bool ctrl=0, bool shift=0);
+void glue_keyPress  (class SampleChannel *ch, bool ctrl=0, bool shift=0);
+void glue_keyPress  (class MidiChannel   *ch, bool ctrl=0, bool shift=0);
+void glue_keyRelease(class Channel       *ch, bool ctrl=0, bool shift=0);
+void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0);
+
+/* start/stopActionRec
+Handles the action recording. If gui == true the signal comes from an user
+interaction, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_startStopActionRec(bool gui=true);
+void glue_startActionRec(bool gui=true);
+void glue_stopActionRec(bool gui=true);
+
+/* start/stopInputRec
+Handles the input recording (take). If gui == true the signal comes from an
+internal interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_startStopInputRec(bool gui=true);
+int  glue_startInputRec    (bool gui=true);
+int  glue_stopInputRec     (bool gui=true);
+
+
+#endif
diff --git a/src/glue/main.cpp b/src/glue/main.cpp
new file mode 100644 (file)
index 0000000..4c3638f
--- /dev/null
@@ -0,0 +1,421 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <cmath>
+#include "../gui/elems/ge_waveform.h"
+#include "../gui/elems/ge_mixed.h"
+#include "../gui/elems/channel.h"
+#include "../gui/elems/sampleChannel.h"
+#include "../gui/elems/ge_waveTools.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_editor.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../utils/gui.h"
+#include "../utils/fs.h"
+#include "../utils/log.h"
+#include "../core/mixerHandler.h"
+#include "../core/mixer.h"
+#include "../core/recorder.h"
+#include "../core/wave.h"
+#include "../core/pluginHost.h"
+#include "../core/channel.h"
+#include "../core/sampleChannel.h"
+#include "../core/midiChannel.h"
+#include "../core/kernelMidi.h"
+#include "../core/patch_DEPR_.h"
+#include "../core/conf.h"
+#include "main.h"
+
+
+extern gdMainWindow *G_MainWin;
+extern Mixer                    G_Mixer;
+extern Recorder                         G_Recorder;
+extern KernelAudio   G_KernelAudio;
+extern KernelMidi    G_KernelMidi;
+extern Patch_DEPR_   G_Patch_DEPR_;
+extern Conf                             G_Conf;
+extern bool                             G_audio_status;
+#ifdef WITH_VST
+extern PluginHost    G_PluginHost;
+#endif
+
+
+void glue_setBpm(const char *v1, const char *v2)
+{
+       char  buf[6];
+       float value = atof(v1) + (atof(v2)/10);
+       if (value < 20.0f)      {
+               value = 20.0f;
+               sprintf(buf, "20.0");
+       }
+       else
+               sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2);
+
+       /* a value such as atof("120.1") will never be 120.1 but 120.0999999,
+        * because of the rounding error. So we pass the real "wrong" value to
+        * G_Mixer and we show the nice looking (but fake) one to the GUI. */
+
+       float old_bpm = G_Mixer.bpm;
+       G_Mixer.bpm = value;
+       G_Mixer.updateFrameBars();
+
+       /* inform recorder and actionEditor of the change */
+
+       G_Recorder.updateBpm(old_bpm, value, G_Mixer.quanto);
+       gu_refreshActionEditor();
+
+       G_MainWin->timing->setBpm(buf);
+       gu_log("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setBeats(int beats, int bars, bool expand)
+{
+       /* temp vars to store old data (they are necessary) */
+
+       int      oldvalue = G_Mixer.beats;
+       unsigned oldfpb         = G_Mixer.totalFrames;
+
+       if (beats > MAX_BEATS)
+               G_Mixer.beats = MAX_BEATS;
+       else if (beats < 1)
+               G_Mixer.beats = 1;
+       else
+               G_Mixer.beats = beats;
+
+       /* update bars - bars cannot be greate than beats and must be a sub
+        * multiple of beats. If not, approximation to the nearest (and greater)
+        * value available. */
+
+       if (bars > G_Mixer.beats)
+               G_Mixer.bars = G_Mixer.beats;
+       else if (bars <= 0)
+               G_Mixer.bars = 1;
+       else if (beats % bars != 0) {
+               G_Mixer.bars = bars + (beats % bars);
+               if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it)
+                       G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars);
+       }
+       else
+               G_Mixer.bars = bars;
+
+       G_Mixer.updateFrameBars();
+
+       /* update recorded actions */
+
+       if (expand) {
+               if (G_Mixer.beats > oldvalue)
+                       G_Recorder.expand(oldfpb, G_Mixer.totalFrames);
+               //else if (G_Mixer.beats < oldvalue)
+               //      G_Recorder.shrink(G_Mixer.totalFrames);
+       }
+
+       G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
+       gu_refreshActionEditor();  // in case the action editor is open
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopSeq(bool gui)
+{
+       G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startSeq(bool gui)
+{
+       G_Mixer.running = true;
+
+       if (gui) {
+#ifdef __linux__
+               G_KernelAudio.jackStart();
+#endif
+       }
+
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) {
+               G_KernelMidi.send(MIDI_START, -1, -1);
+               G_KernelMidi.send(MIDI_POSITION_PTR, 0, 0);
+       }
+
+       if (!gui) {
+    Fl::lock();
+    G_MainWin->controller->updatePlay(1);
+    Fl::unlock();
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopSeq(bool gui)
+{
+       mh_stopSequencer();
+
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
+               G_KernelMidi.send(MIDI_STOP, -1, -1);
+
+#ifdef __linux__
+       if (gui)
+               G_KernelAudio.jackStop();
+#endif
+
+       /* what to do if we stop the sequencer and some action recs are active?
+        * Deactivate the button and delete any 'rec on' status */
+
+       if (G_Recorder.active) {
+               G_Recorder.active = false;
+    Fl::lock();
+         G_MainWin->controller->updateRecAction(0);
+         Fl::unlock();
+       }
+
+       /* if input recs are active (who knows why) we must deactivate them.
+        * One might stop the sequencer while an input rec is running. */
+
+       if (G_Mixer.recording) {
+               mh_stopInputRec();
+    Fl::lock();
+         G_MainWin->controller->updateRecInput(0);
+         Fl::unlock();
+       }
+
+       if (!gui) {
+    Fl::lock();
+         G_MainWin->controller->updatePlay(0);
+         Fl::unlock();
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_rewindSeq()
+{
+       mh_rewindSequencer();
+       if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M)
+               G_KernelMidi.send(MIDI_POSITION_PTR, 0, 0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopReadingRecs(SampleChannel *ch, bool gui)
+{
+       /* When you call glue_startReadingRecs with G_Conf.treatRecsAsLoops, the
+       member value ch->readActions actually is not set to true immediately, because
+       the channel is in wait mode (REC_WAITING). ch->readActions will become true on
+       the next first beat. So a 'stop rec' command should occur also when
+       ch->readActions is false but the channel is in wait mode; this check will
+       handle the case of when you press 'R', the channel goes into REC_WAITING and
+       then you press 'R' again to undo the status. */
+
+       if (ch->readActions || (!ch->readActions && ch->recStatus == REC_WAITING))
+               glue_stopReadingRecs(ch, gui);
+       else
+               glue_startReadingRecs(ch, gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startReadingRecs(SampleChannel *ch, bool gui)
+{
+       if (G_Conf.treatRecsAsLoops)
+               ch->recStatus = REC_WAITING;
+       else
+               ch->setReadActions(true, G_Conf.recsStopOnChanHalt);
+       if (!gui) {
+               Fl::lock();
+               ((geSampleChannel*)ch->guiChannel)->readActions->value(1);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_stopReadingRecs(SampleChannel *ch, bool gui)
+{
+       /* First of all, if the mixer is not running just stop and disable everything.
+       Then if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put the
+       channel in REC_ENDING status. */
+
+       if (!G_Mixer.running) {
+               ch->recStatus = REC_STOPPED;
+               ch->readActions = false;
+       }
+       else
+       if (G_Conf.treatRecsAsLoops)
+               ch->recStatus = REC_ENDING;
+       else
+               ch->setReadActions(false, G_Conf.recsStopOnChanHalt);
+
+       if (!gui) {
+               Fl::lock();
+               ((geSampleChannel*)ch->guiChannel)->readActions->value(0);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_quantize(int val)
+{
+       G_Mixer.quantize = val;
+       G_Mixer.updateQuanto();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setOutVol(float v, bool gui)
+{
+       G_Mixer.outVol = v;
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->inOut->setOutVol(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setInVol(float v, bool gui)
+{
+       G_Mixer.inVol = v;
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->inOut->setInVol(v);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_clearAllSamples()
+{
+       G_Mixer.running = false;
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
+               G_Mixer.channels.at(i)->empty();
+               G_Mixer.channels.at(i)->guiChannel->reset();
+       }
+       G_Recorder.init();
+       return;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_clearAllRecs()
+{
+       G_Recorder.init();
+       gu_updateControls();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_resetToInitState(bool resetGui, bool createColumns)
+{
+       G_Patch_DEPR_.setDefault();
+       G_Mixer.close();
+       G_Mixer.init();
+       G_Recorder.init();
+#ifdef WITH_VST
+       G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins);
+#endif
+
+       G_MainWin->keyboard->clear();
+       if (createColumns)
+               G_MainWin->keyboard->init();
+
+  gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
+
+       if (resetGui)
+               gu_updateControls();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_startStopMetronome(bool gui)
+{
+       G_Mixer.metronome = !G_Mixer.metronome;
+       if (!gui) {
+               Fl::lock();
+               G_MainWin->controller->updateMetronome(G_Mixer.metronome);
+               Fl::unlock();
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* never expand or shrink recordings (last param of setBeats = false):
+ * this is live manipulation */
+
+void glue_beatsMultiply()
+{
+       glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false);
+}
+
+void glue_beatsDivide()
+{
+       glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false);
+}
diff --git a/src/glue/main.h b/src/glue/main.h
new file mode 100644 (file)
index 0000000..422f422
--- /dev/null
@@ -0,0 +1,81 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * glue
+ * Intermediate layer GUI <-> CORE.
+ *
+ * How to know if you need another glue_ function? Ask yourself if the
+ * new action will ever be called via MIDI or keyboard/mouse. If yes,
+ * put it here.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#ifndef GLUE_H
+#define GLUE_H
+
+
+void glue_setBpm(const char *v1, const char *v2);
+void glue_setBeats(int beats, int bars, bool expand);
+
+/* start, stop, rewind sequencer
+If gui == true the signal comes from an user interaction on the GUI,
+otherwise it's a MIDI/Jack/external signal. */
+
+void glue_startStopSeq(bool gui=true);
+void glue_startSeq    (bool gui=true);
+void glue_stopSeq     (bool gui=true);
+void glue_rewindSeq   ();
+
+/* start/stopReadingRecs
+Handles the 'R' button. If gui == true the signal comes from an user interaction
+on the GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true);
+void glue_startReadingRecs    (class SampleChannel *ch, bool gui=true);
+void glue_stopReadingRecs     (class SampleChannel *ch, bool gui=true);
+
+void glue_quantize(int val);
+
+void glue_setOutVol (float v, bool gui=true);
+void glue_setInVol  (float v, bool gui=true);
+
+void glue_clearAllSamples();
+void glue_clearAllRecs();
+
+/* resetToInitState
+ * reset Giada to init state. If resetGui also refresh all widgets. If
+ * createColumns also build initial empty columns. */
+
+void glue_resetToInitState(bool resetGui=true, bool createColumns=true);
+
+void glue_startStopMetronome(bool gui=true);
+
+/* beatsDivide/Multiply
+ * shrinks or enlarges the number of beats by 2. */
+
+void glue_beatsMultiply();
+void glue_beatsDivide();
+
+#endif
index d51773693fc5d90a6e179b0bedc749640b0efde8..41924d914d4094d00edbff63e2e59835954bb574 100644 (file)
 #include "../core/sampleChannel.h"
 #include "../core/midiChannel.h"
 #include "../core/wave.h"
-#include "../utils/gui_utils.h"
-#include "glue.h" // TODO - remove, used only for DEPR calls
+#include "../utils/gui.h"
+#include "../utils/log.h"
+#include "main.h" // TODO - remove, used only for DEPR calls
 #include "channel.h"
 #include "storage.h"
 
 
 using std::string;
+using std::vector;
 
 
-extern gdMainWindow *mainWin;
+extern gdMainWindow *G_MainWin;
 extern Mixer                    G_Mixer;
+extern Recorder                         G_Recorder;
 extern Patch         G_Patch;
 extern Conf          G_Conf;
 extern Patch_DEPR_   G_Patch_DEPR_; // TODO - remove, used only for DEPR calls
@@ -87,8 +90,8 @@ static void __glue_fillPatchGlobalsPlugins__(vector <Plugin *> *host, vector<Pat
 
 static void __glue_fillPatchColumns__()
 {
-       for (unsigned i=0; i<mainWin->keyboard->getTotalColumns(); i++) {
-               gColumn *gCol = mainWin->keyboard->getColumn(i);
+       for (unsigned i=0; i<G_MainWin->keyboard->getTotalColumns(); i++) {
+               gColumn *gCol = G_MainWin->keyboard->getColumn(i);
                Patch::column_t pCol;
                pCol.index = gCol->getIndex();
                pCol.width = gCol->w();
@@ -160,8 +163,8 @@ static bool __glue_savePatch__(const string &fullPath, const string &name,
        __glue_fillPatchColumns__();
 
        if (G_Patch.write(fullPath)) {
-               gu_update_win_label(name.c_str());
-               gLog("[glue_savePatch] patch saved as %s\n", fullPath.c_str());
+               gu_updateMainWinLabel(name);
+               gu_log("[glue_savePatch] patch saved as %s\n", fullPath.c_str());
                return true;
        }
        return false;
@@ -175,19 +178,19 @@ void glue_savePatch(void *data)
 {
        gdSaveBrowser *browser = (gdSaveBrowser*) data;
        string name            = browser->getName();
-       string fullPath        = browser->getCurrentPath() + G_SLASH + gStripExt(name) + ".gptc";
+       string fullPath        = browser->getCurrentPath() + G_SLASH + gu_stripExt(name) + ".gptc";
 
        if (name == "") {
                gdAlert("Please choose a file name.");
                return;
        }
 
-       if (gFileExists(fullPath.c_str()))
+       if (gu_fileExists(fullPath))
                if (!gdConfirmWin("Warning", "File exists: overwrite?"))
                        return;
 
        if (__glue_savePatch__(fullPath, name, false)) {  // false == not a project
-               G_Conf.patchPath = gDirname(fullPath);
+               G_Conf.patchPath = gu_dirname(fullPath);
                browser->do_callback();
        }
        else
@@ -202,16 +205,16 @@ void glue_loadPatch(void *data)
 {
        gdLoadBrowser *browser = (gdLoadBrowser*) data;
        string fullPath        = browser->getSelectedItem();
-       bool isProject         = gIsProject(browser->getSelectedItem());
+       bool isProject         = gu_isProject(browser->getSelectedItem());
 
        browser->showStatusBar();
 
-       gLog("[glue] loading %s...\n", fullPath.c_str());
+       gu_log("[glue] loading %s...\n", fullPath.c_str());
 
        string fileToLoad = fullPath;  // patch file to read from
        string basePath   = "";        // base path, in case of reading from a project
        if (isProject) {
-               fileToLoad = fullPath + G_SLASH + gStripExt(gBasename(fullPath)) + ".gptc";
+               fileToLoad = fullPath + G_SLASH + gu_stripExt(gu_basename(fullPath)) + ".gptc";
                basePath   = fullPath + G_SLASH;
        }
 
@@ -222,9 +225,9 @@ void glue_loadPatch(void *data)
        bool deprecated = false;
 
        if (res == PATCH_UNREADABLE) {
-               gLog("[glue] failed reading JSON-based patch. Trying with the deprecated method\n");
+               gu_log("[glue] failed reading JSON-based patch. Trying with the deprecated method\n");
                deprecated = true;
-               res = glue_loadPatch__DEPR__(gBasename(fileToLoad).c_str(), fileToLoad.c_str(),
+               res = glue_loadPatch__DEPR__(gu_basename(fileToLoad).c_str(), fileToLoad.c_str(),
                                browser->getStatusBar(), isProject);
        }
 
@@ -263,7 +266,7 @@ void glue_loadPatch(void *data)
        float steps = 0.8 / G_Patch.channels.size();
        for (unsigned i=0; i<G_Patch.columns.size(); i++) {
                Patch::column_t *col = &G_Patch.columns.at(i);
-               mainWin->keyboard->addColumn(col->width);
+               G_MainWin->keyboard->addColumn(col->width);
                for (unsigned k=0; k<G_Patch.channels.size(); k++) {
                        if (G_Patch.channels.at(k).column == col->index) {
                                Channel *ch = glue_addChannel(G_Patch.channels.at(k).column,
@@ -283,22 +286,22 @@ void glue_loadPatch(void *data)
        /* let recorder recompute the actions' positions if the current
         * samplerate != patch samplerate */
 
-       recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate);
+       G_Recorder.updateSamplerate(G_Conf.samplerate, G_Patch.samplerate);
 
        /* save patchPath by taking the last dir of the broswer, in order to
         * reuse it the next time */
 
-       G_Conf.patchPath = gDirname(fullPath);
+       G_Conf.patchPath = gu_dirname(fullPath);
 
        /* refresh GUI */
 
        gu_updateControls();
-       gu_update_win_label(G_Patch.name.c_str());
+       gu_updateMainWinLabel(G_Patch.name);
 
        browser->setStatusBar(0.1f);
        //__glue_setProgressBar__(status, 1.0f);
 
-       gLog("[glue] patch loaded successfully\n");
+       gu_log("[glue] patch loaded successfully\n");
 
 #ifdef WITH_VST
 
@@ -346,12 +349,12 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat
 
        /* mixerHandler will update the samples inside Mixer */
 
-       mh_loadPatch_DEPR_(isProject, gDirname(fpath).c_str());
+       mh_loadPatch_DEPR_(isProject, gu_dirname(fpath).c_str());
 
        /* take the patch name and update the main window's title */
 
        G_Patch_DEPR_.getName();
-       gu_update_win_label(G_Patch_DEPR_.name);
+       gu_updateMainWinLabel(G_Patch_DEPR_.name);
 
        status->value(0.4f);  // progress status: 0.4
        //Fl::check();
@@ -372,7 +375,7 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat
        /* this one is vital: let recorder recompute the actions' positions if
         * the current samplerate != patch samplerate */
 
-       recorder::updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate);
+       G_Recorder.updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate);
 
        /* update gui */
 
@@ -385,9 +388,9 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat
        /* save patchPath by taking the last dir of the broswer, in order to
         * reuse it the next time */
 
-       G_Conf.patchPath = gDirname(fpath).c_str();
+       G_Conf.patchPath = gu_dirname(fpath).c_str();
 
-       gLog("[glue] patch %s loaded\n", fname);
+       gu_log("[glue] patch %s loaded\n", fname);
 
 #ifdef WITH_VST
        if (resPlugins != 1)
@@ -408,22 +411,22 @@ void glue_saveProject(void *data)
        gdSaveBrowser *browser = (gdSaveBrowser*) data;
        string name            = browser->getName();
        string folderPath      = browser->getCurrentPath(); //browser->getSelectedItem();
-       string fullPath        = folderPath + G_SLASH + gStripExt(name) + ".gprj";
+       string fullPath        = folderPath + G_SLASH + gu_stripExt(name) + ".gprj";
 
        if (name == "") {
                gdAlert("Please choose a project name.");
                return;
        }
 
-       if (gIsProject(fullPath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?"))
+       if (gu_isProject(fullPath) && !gdConfirmWin("Warning", "Project exists: overwrite?"))
                return;
 
-       if (!gDirExists(fullPath.c_str()) && !gMkdir(fullPath.c_str())) {
-               gLog("[glue_saveProject] unable to make project directory!\n");
+       if (!gu_dirExists(fullPath) && !gu_mkdir(fullPath)) {
+               gu_log("[glue_saveProject] unable to make project directory!\n");
                return;
        }
 
-       gLog("[glue_saveProject] project dir created: %s\n", fullPath.c_str());
+       gu_log("[glue_saveProject] project dir created: %s\n", fullPath.c_str());
 
        /* copy all samples inside the folder. Takes and logical ones are saved
         * via glue_saveSample() */
@@ -443,13 +446,13 @@ void glue_saveProject(void *data)
 
                string samplePath = fullPath + G_SLASH + ch->wave->basename(true);
 
-               if (gFileExists(samplePath.c_str()))
+               if (gu_fileExists(samplePath))
                        remove(samplePath.c_str());
                if (ch->save(samplePath.c_str()))
                        ch->wave->pathfile = samplePath;
        }
 
-       string gptcPath = fullPath + G_SLASH + gStripExt(name.c_str()) + ".gptc";
+       string gptcPath = fullPath + G_SLASH + gu_stripExt(name) + ".gptc";
        if (__glue_savePatch__(gptcPath, name, true)) // true == it's a project
                browser->do_callback();
        else
@@ -471,12 +474,12 @@ void glue_loadSample(void *data)
        int res = glue_loadChannel((SampleChannel*) browser->getChannel(), fullPath.c_str());
 
        if (res == SAMPLE_LOADED_OK) {
-               G_Conf.samplePath = gDirname(fullPath);
+               G_Conf.samplePath = gu_dirname(fullPath);
                browser->do_callback();
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open
+               G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open
        }
        else
-               mainWin->keyboard->printChannelMessage(res);
+               G_MainWin->keyboard->printChannelMessage(res);
 }
 
 
@@ -496,14 +499,14 @@ void glue_saveSample(void *data)
 
        /* bruteforce check extension. */
 
-       string filePath = folderPath + G_SLASH + gStripExt(name) + ".wav";
+       string filePath = folderPath + G_SLASH + gu_stripExt(name) + ".wav";
 
-       if (gFileExists(filePath))
+       if (gu_fileExists(filePath))
                if (!gdConfirmWin("Warning", "File exists: overwrite?"))
                        return;
 
        if (((SampleChannel*)browser->getChannel())->save(filePath.c_str())) {
-               G_Conf.samplePath = gDirname(folderPath);
+               G_Conf.samplePath = gu_dirname(folderPath);
                browser->do_callback();
        }
        else
index 98be8e8cb64baae174a1a0939e51810061972350..a95ec0a294c24ddcc6a966951b72f54d27a7a04f 100644 (file)
 #define GLUE_STORAGE_H
 
 
-#include <vector>
-#include "../core/patch.h"
-
-
-using std::string;
-using std::vector;
-
-
 void glue_loadPatch  (void *data);
 int glue_loadPatch__DEPR__(const char *fname, const char *fpath, class gProgress *status, bool isProject);
 void glue_savePatch  (void *data);
@@ -47,4 +39,5 @@ void glue_saveProject(void *data);
 void glue_saveSample (void *data);
 void glue_loadSample (void *data);
 
+
 #endif
index 3e0e61424acb4ae136b583f38a0823dbeae2b8c5..5c42d261d7073b48e984c7ad4cca1c571cc2eafc 100644 (file)
 #include "../../core/kernelAudio.h"
 #include "../../core/kernelMidi.h"
 #include "../../core/graphics.h"
-#include "../../utils/gui_utils.h"
+#include "../../deps/juce/config.h"
+#include "../../utils/gui.h"
 #include "../elems/ge_mixed.h"
 #include "gd_about.h"
 
 
-extern Conf G_Conf;
+extern Conf        G_Conf;
+extern KernelAudio G_KernelAudio;
+extern KernelMidi  G_KernelMidi;
 
 
 gdAbout::gdAbout()
@@ -85,8 +88,8 @@ gdAbout::gdAbout()
                "News, infos, contacts and documentation:\n"
                "www.giadamusic.com",
                FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION,
-               kernelAudio::getRtAudioVersion().c_str(),
-               kernelMidi::getRtMidiVersion().c_str(),
+               G_KernelAudio.getRtAudioVersion().c_str(),
+               G_KernelMidi.getRtMidiVersion().c_str(),
                JANSSON_VERSION
 #ifdef WITH_VST
                , JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER);
index 241674050bdb03dd8452796583160f08048172ec..2b8b6d333441c276bc5f08eb9a9817d767bab8ba 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_about
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef GD_ABOUT_H
 #define GD_ABOUT_H
 
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
+
 #include "../elems/ge_window.h"
 
 
-class gdAbout : public gWindow {
+class gdAbout : public gWindow
+{
 private:
+
        class gBox       *logo;
        class gBox       *text;
        class gClick *close;
@@ -47,12 +48,12 @@ private:
 #endif
 
 public:
+
        gdAbout();
        ~gdAbout();
 
        static void cb_close(Fl_Widget *w, void *p);
        inline void __cb_close();
-
 };
 
 #endif
index ddfcdafc1599f12c2a84615f2461f898b7bc130a..9d705066dd6a0b32f97972185fa5de81d035588d 100644 (file)
 
 
 #include <math.h>
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/graphics.h"
 #include "../../core/mixer.h"
 #include "../../core/recorder.h"
 #include "../../core/conf.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
-#include "../elems/ge_actionChannel.h"
-#include "../elems/ge_muteChannel.h"
-#include "../elems/ge_envelopeChannel.h"
-#include "../elems/ge_pianoRoll.h"
+#include "../elems/actionEditor.h"
+#include "../elems/envelopeEditor.h"
+#include "../elems/muteEditor.h"
+#include "../elems/noteEditor.h"
 #include "../elems/ge_mixed.h"
 #include "gd_actionEditor.h"
 
@@ -100,9 +100,9 @@ gdActionEditor::gdActionEditor(Channel *chan)
 
                SampleChannel *ch = (SampleChannel*) chan;
 
-               ac = new gActionChannel     (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch);
-               mc = new gMuteChannel       (scroller->x(), ac->y()+ac->h()+8, this);
-               vc = new gEnvelopeChannel   (scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume");
+               ac = new geActionEditor  (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch);
+               mc = new geMuteEditor    (scroller->x(), ac->y()+ac->h()+8, this);
+               vc = new geEnvelopeEditor(scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume");
                scroller->add(ac);
                //scroller->add(new gResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8));
                scroller->add(mc);
@@ -121,7 +121,7 @@ gdActionEditor::gdActionEditor(Channel *chan)
                        ac->deactivate();
        }
        else {
-               pr = new gPianoRollContainer(scroller->x(), upperArea->y()+upperArea->h()+8, this);
+               pr = new geNoteEditor(scroller->x(), upperArea->y()+upperArea->h()+8, this);
                scroller->add(pr);
                scroller->add(new gResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8));
        }
index 1f7eb40cbd8a8ec8b543b1fe357898e3ff7482a8..435619d7f3530de36d71e6f70c4577c9196a9cba 100644 (file)
@@ -45,8 +45,8 @@ using std::vector;
  * This class calculates chan, zoom, frames per beat, and so on. Each
  * sub-widget contains a pointer to this window to query those data. */
 
-class gdActionEditor : public gWindow {
-
+class gdActionEditor : public gWindow
+{
 private:
 
        /* update
@@ -74,10 +74,10 @@ public:
        class gClick    *zoomOut;
        class gScroll   *scroller;       // widget container
 
-       class gActionChannel      *ac;
-       class gMuteChannel        *mc;
-       class gEnvelopeChannel    *vc;
-       class gPianoRollContainer *pr;
+       class geActionEditor   *ac;
+       class geMuteEditor     *mc;
+       class geEnvelopeEditor *vc;
+       class geNoteEditor     *pr;
 
        vector <class gActionWidget*> widgets;
 
index 36599ebff89bfc8f7b0302d01e09f5b1a3a21959..e77e83999111ba47f5336b17451ca29c9d2800e6 100644 (file)
  * ------------------------------------------------------------------ */
 
 
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/mixer.h"
 #include "../../core/conf.h"
-#include "../../glue/glue.h"
+#include "../../core/const.h"
+#include "../../glue/main.h"
 #include "gd_beatsInput.h"
 #include "gd_mainWindow.h"
 
index d0186bf1179a891729555f0a1f02331fa34d2355..4ad1da2e0c1824658120a24552f599a65da6b1e6 100644 (file)
 
 
 #include "../../core/conf.h"
+#include "../../core/const.h"
 #include "../../core/mixer.h"
-#include "../../glue/glue.h"
-#include "../../utils/gui_utils.h"
+#include "../../glue/main.h"
+#include "../../utils/gui.h"
 #include "../elems/ge_mixed.h"
 #include "gd_bpmInput.h"
 #include "gd_mainWindow.h"
index 448ad7495ebea368906be2866a2a49756a6c18fe..0c45a1824209cb7bd8f811985651aa516c244a7e 100644 (file)
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
 #include "../../core/conf.h"
-#include "../../glue/glue.h"
+#include "../../core/const.h"
+#include "../../glue/main.h"
 #include "../../glue/channel.h"
 #include "../../glue/storage.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../elems/ge_browser.h"
-#include "../elems/ge_channel.h"
+#include "../elems/channel.h"
 #include "gd_browser.h"
 
 
@@ -102,7 +103,7 @@ gdBaseBrowser::~gdBaseBrowser()
        G_Conf.browserW = w();
        G_Conf.browserH = h();
        G_Conf.browserPosition = browser->position();
-       G_Conf.browserLastPath = gDirname(browser->getSelectedItem());
+       G_Conf.browserLastPath = gu_dirname(browser->getSelectedItem());
        G_Conf.browserLastValue = browser->value();
 }
 
@@ -197,7 +198,7 @@ void gdSaveBrowser::__cb_down()
        /* if the selected item is a directory just load its content. If it's a file
         * use it as the file name (i.e. fill name->value()). */
 
-       if (gIsDir(path)) {
+       if (gu_isDir(path)) {
                browser->loadDir(path);
                where->value(browser->getCurrentDir().c_str());
        }
@@ -261,7 +262,7 @@ void gdLoadBrowser::__cb_down()
 {
        string path = browser->getSelectedItem();
 
-       if (path.empty() || !gIsDir(path)) // when click on an empty area or not a dir
+       if (path.empty() || !gu_isDir(path)) // when click on an empty area or not a dir
                return;
 
        browser->loadDir(path);
index 5d7da03e7324ee975f22e81a12ac0777e08a95f5..832b75a5448211736e55eb367e01d736a449539e 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <RtMidi.h>
+#include <FL/Fl_Tabs.H>
 #include "../../core/conf.h"
 #include "../../core/midiMapConf.h"
 #include "../../core/patch_DEPR_.h"
 #include "../../core/kernelAudio.h"
 #include "../../core/kernelMidi.h"
 #include "../../core/pluginHost.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../utils/log.h"
+#include "../../utils/string.h"
 #include "../elems/ge_mixed.h"
 #include "gd_config.h"
 #include "gd_keyGrabber.h"
@@ -44,6 +47,8 @@
 
 extern Patch_DEPR_ G_Patch_DEPR_;
 extern Conf           G_Conf;
+extern KernelAudio G_KernelAudio;
+extern KernelMidi  G_KernelMidi;
 extern bool        G_audio_status;
 extern MidiMapConf G_MidiMap;
 
@@ -131,11 +136,11 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
 
 #if defined(__linux__)
 
-       if (kernelAudio::hasAPI(RtAudio::LINUX_ALSA))
+       if (G_KernelAudio.hasAPI(RtAudio::LINUX_ALSA))
                soundsys->add("ALSA");
-       if (kernelAudio::hasAPI(RtAudio::UNIX_JACK))
+       if (G_KernelAudio.hasAPI(RtAudio::UNIX_JACK))
                soundsys->add("Jack");
-       if (kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
+       if (G_KernelAudio.hasAPI(RtAudio::LINUX_PULSE))
                soundsys->add("PulseAudio");
 
        switch (G_Conf.soundSystem) {
@@ -157,11 +162,11 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
 
 #elif defined(_WIN32)
 
-       if (kernelAudio::hasAPI(RtAudio::WINDOWS_DS))
+       if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_DS))
                soundsys->add("DirectSound");
-       if (kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO))
+       if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_ASIO))
                soundsys->add("ASIO");
-       if (kernelAudio::hasAPI(RtAudio::WINDOWS_WASAPI))
+       if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_WASAPI))
                soundsys->add("WASAPI");
 
        switch (G_Conf.soundSystem) {
@@ -181,7 +186,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
 
 #elif defined (__APPLE__)
 
-       if (kernelAudio::hasAPI(RtAudio::MACOSX_CORE))
+       if (G_KernelAudio.hasAPI(RtAudio::MACOSX_CORE))
                soundsys->add("CoreAudio");
 
        switch (G_Conf.soundSystem) {
@@ -213,10 +218,10 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
                /* fill frequency dropdown menu */
                /* TODO - add fetchFrequencies() */
 
-               int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value());
+               int nfreq = G_KernelAudio.getTotalFreqs(sounddevOut->value());
                for (int i=0; i<nfreq; i++) {
-                       int freq = kernelAudio::getFreq(sounddevOut->value(), i);
-                       samplerate->add(gItoa(freq).c_str());
+                       int freq = G_KernelAudio.getFreq(sounddevOut->value(), i);
+                       samplerate->add(gu_itoa(freq).c_str());
                        if (freq == G_Conf.samplerate)
                                samplerate->value(i);
                }
@@ -241,7 +246,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
        buffersize->add("1024");
        buffersize->add("2048");
        buffersize->add("4096");
-       buffersize->showItem(gItoa(G_Conf.buffersize).c_str());
+       buffersize->showItem(gu_itoa(G_Conf.buffersize).c_str());
 
        rsmpQuality->add("Sinc best quality (very slow)");
        rsmpQuality->add("Sinc medium quality (slow)");
@@ -250,7 +255,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
        rsmpQuality->add("Linear (very fast)");
        rsmpQuality->value(G_Conf.rsmpQuality);
 
-       delayComp->value(gItoa(G_Conf.delayComp).c_str());
+       delayComp->value(gu_itoa(G_Conf.delayComp).c_str());
        delayComp->type(FL_INT_INPUT);
        delayComp->maximum_size(5);
 
@@ -293,7 +298,7 @@ void gTabAudio::__cb_fetchOutChans()
 
 void gTabAudio::__cb_showInputInfo()
 {
-       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       unsigned dev = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value()));
        new gdDevInfo(dev);
 }
 
@@ -303,7 +308,7 @@ void gTabAudio::__cb_showInputInfo()
 
 void gTabAudio::__cb_showOutputInfo()
 {
-       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       unsigned dev = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value()));
        new gdDevInfo(dev);
 }
 
@@ -374,8 +379,8 @@ void gTabAudio::fetchInChans(int menuItem)
 
        channelsIn->clear();
 
-       unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       unsigned chs = kernelAudio::getMaxInChans(dev);
+       unsigned dev = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       unsigned chs = G_KernelAudio.getMaxInChans(dev);
 
        if (chs == 0) {
                channelsIn->add("none");
@@ -398,8 +403,8 @@ void gTabAudio::fetchOutChans(int menuItem)
 {
        channelsOut->clear();
 
-       unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       unsigned chs = kernelAudio::getMaxOutChans(dev);
+       unsigned dev = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       unsigned chs = G_KernelAudio.getMaxOutChans(dev);
 
        if (chs == 0) {
                channelsOut->add("none");
@@ -427,11 +432,11 @@ int gTabAudio::findMenuDevice(gChoice *m, int device)
                return 0;
 
        for (int i=0; i<m->size(); i++) {
-               if (kernelAudio::getDeviceName(device) == "")
+               if (G_KernelAudio.getDeviceName(device) == "")
                        continue;
                if (m->text(i) == NULL)
                        continue;
-               if (m->text(i) == kernelAudio::getDeviceName(device))
+               if (m->text(i) == G_KernelAudio.getDeviceName(device))
                        return i;
        }
 
@@ -444,7 +449,7 @@ int gTabAudio::findMenuDevice(gChoice *m, int device)
 
 void gTabAudio::fetchSoundDevs()
 {
-       if (kernelAudio::numDevs == 0) {
+       if (G_KernelAudio.numDevs == 0) {
                sounddevOut->add("-- no devices found --");
                sounddevOut->value(0);
                sounddevIn->add("-- no devices found --");
@@ -462,11 +467,11 @@ void gTabAudio::fetchSoundDevs()
 
                sounddevIn->add("(disabled)");
 
-               for (unsigned i=0; i<kernelAudio::numDevs; i++) {
+               for (unsigned i=0; i<G_KernelAudio.numDevs; i++) {
 
                        /* escaping '/', very dangerous in FLTK (it creates a submenu) */
 
-                       string tmp = kernelAudio::getDeviceName(i);
+                       string tmp = G_KernelAudio.getDeviceName(i);
                        for (unsigned k=0; k<tmp.size(); k++)
                                if (tmp[k] == '/' || tmp[k] == '|' || tmp[k] == '&' || tmp[k] == '_')
                                        tmp[k] = '-';
@@ -475,10 +480,10 @@ void gTabAudio::fetchSoundDevs()
                         * way we can filter devices only for input or output, e.g. an input
                         * devices has 0 output channels. */
 
-                       if (kernelAudio::getMaxOutChans(i) > 0)
+                       if (G_KernelAudio.getMaxOutChans(i) > 0)
                                sounddevOut->add(tmp.c_str());
 
-                       if (kernelAudio::getMaxInChans(i) > 0)
+                       if (G_KernelAudio.getMaxInChans(i) > 0)
                                sounddevIn->add(tmp.c_str());
                }
 
@@ -534,6 +539,8 @@ void gTabAudio::save()
                G_Conf.soundSystem = SYS_API_DS;
        else if (text == "ASIO")
                G_Conf.soundSystem = SYS_API_ASIO;
+       else if (text == "WASAPI")
+               G_Conf.soundSystem = SYS_API_WASAPI;
 
 #elif defined (__APPLE__)
 
@@ -544,8 +551,8 @@ void gTabAudio::save()
 
        /* use the device name to search into the drop down menu's */
 
-       G_Conf.soundDeviceOut = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       G_Conf.soundDeviceIn  = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
+       G_Conf.soundDeviceOut = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value()));
+       G_Conf.soundDeviceIn  = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value()));
        G_Conf.channelsOut    = channelsOut->value();
        G_Conf.channelsIn     = channelsIn->value();
        G_Conf.limitOutput    = limitOutput->value();
@@ -620,7 +627,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H)
 
 void gTabMidi::fetchOutPorts() {
 
-       if (kernelMidi::numOutPorts == 0) {
+       if (G_KernelMidi.numOutPorts == 0) {
                portOut->add("-- no ports found --");
                portOut->value(0);
                portOut->deactivate();
@@ -629,8 +636,8 @@ void gTabMidi::fetchOutPorts() {
 
                portOut->add("(disabled)");
 
-               for (unsigned i=0; i<kernelMidi::numOutPorts; i++)
-                       portOut->add(gu_removeFltkChars(kernelMidi::getOutPortName(i)).c_str());
+               for (unsigned i=0; i<G_KernelMidi.numOutPorts; i++)
+                       portOut->add(gu_removeFltkChars(G_KernelMidi.getOutPortName(i)).c_str());
 
                portOut->value(G_Conf.midiPortOut+1);    // +1 because midiPortOut=-1 is '(disabled)'
        }
@@ -641,7 +648,7 @@ void gTabMidi::fetchOutPorts() {
 
 void gTabMidi::fetchInPorts()
 {
-       if (kernelMidi::numInPorts == 0) {
+       if (G_KernelMidi.numInPorts == 0) {
                portIn->add("-- no ports found --");
                portIn->value(0);
                portIn->deactivate();
@@ -650,8 +657,8 @@ void gTabMidi::fetchInPorts()
 
                portIn->add("(disabled)");
 
-               for (unsigned i=0; i<kernelMidi::numInPorts; i++)
-                       portIn->add(gu_removeFltkChars(kernelMidi::getInPortName(i)).c_str());
+               for (unsigned i=0; i<G_KernelMidi.numInPorts; i++)
+                       portIn->add(gu_removeFltkChars(G_KernelMidi.getInPortName(i)).c_str());
 
                portIn->value(G_Conf.midiPortIn+1);    // +1 because midiPortIn=-1 is '(disabled)'
        }
@@ -678,7 +685,7 @@ void gTabMidi::fetchMidiMaps()
        }
 
        /* Preselect the 0 midimap if nothing is selected but midimaps exist. */
-       
+
        if (midiMap->value() == -1 && G_MidiMap.maps.size() > 0)
                midiMap->value(0);
 }
@@ -722,14 +729,14 @@ void gTabMidi::fetchSystems()
 {
 #if defined(__linux__)
 
-       if (kernelMidi::hasAPI(RtMidi::LINUX_ALSA))
+       if (G_KernelMidi.hasAPI(RtMidi::LINUX_ALSA))
                system->add("ALSA");
-       if (kernelMidi::hasAPI(RtMidi::UNIX_JACK))
+       if (G_KernelMidi.hasAPI(RtMidi::UNIX_JACK))
                system->add("Jack");
 
 #elif defined(_WIN32)
 
-       if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM))
+       if (G_KernelMidi.hasAPI(RtMidi::WINDOWS_MM))
                system->add("Multimedia MIDI");
 
 #elif defined (__APPLE__)
@@ -887,7 +894,7 @@ gTabPlugins::gTabPlugins(int X, int Y, int W, int H)
 
 void gTabPlugins::updateCount()
 {
-       string scanLabel = "Scan (" + gItoa(G_PluginHost.countAvailablePlugins()) + " found)";
+       string scanLabel = "Scan (" + gu_itoa(G_PluginHost.countAvailablePlugins()) + " found)";
        scanButton->label(scanLabel.c_str());
 }
 
@@ -903,7 +910,7 @@ void gTabPlugins::cb_scan(Fl_Widget *w, void *p) { ((gTabPlugins*)p)->__cb_scan(
 
 void gTabPlugins::cb_onScan(float progress, void *p)
 {
-       string l = "Scan in progress (" + gItoa((int)(progress*100)) + "%). Please wait...";
+       string l = "Scan in progress (" + gu_itoa((int)(progress*100)) + "%). Please wait...";
        ((gTabPlugins *)p)->info->label(l.c_str());
        Fl::wait();
 }
@@ -916,7 +923,7 @@ void gTabPlugins::__cb_scan(Fl_Widget *w)
 {
        info->show();
        G_PluginHost.scanDir(folderPath->value(), cb_onScan, (void*) this);
-       G_PluginHost.saveList(gGetHomePath() + G_SLASH + "plugins.xml");
+       G_PluginHost.saveList(gu_getHomePath() + G_SLASH + "plugins.xml");
        info->hide();
        updateCount();
 }
index d2e7580acbdae554019f39c5680f0cb40a081a10..fc7b64ae30ac0c37b6ecdd87b84efa69358ced86 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_config
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
+
 
 #ifndef GD_CONFIG_H
 #define GD_CONFIG_H
 
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Tabs.H>
-#include "../elems/ge_window.h"
-
 
-using std::string;
+#include "../elems/ge_window.h"
 
 
 class gdConfig : public gWindow
index 5055928fb6865fef50a185af4d076323d2f86261..3f901a34d57194a601997fbf592df168553b4957 100644 (file)
 
 
 #include "../../core/kernelAudio.h"
-#include "../../utils/gui_utils.h"
-#include "../../utils/utils.h"
+#include "../../utils/gui.h"
+#include "../../utils/string.h"
 #include "../elems/ge_mixed.h"
 #include "gd_devInfo.h"
 
 
+extern KernelAudio G_KernelAudio;
+
+
 using std::string;
 
 
 gdDevInfo::gdDevInfo(unsigned dev)
-: Fl_Window(340, 300, "Device information") {
+       : Fl_Window(340, 300, "Device information")
+{
        set_modal();
 
        text  = new gBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
@@ -48,22 +52,22 @@ gdDevInfo::gdDevInfo(unsigned dev)
        string body  = "";
        int    lines = 7;
 
-       body  = "Device name: " + kernelAudio::getDeviceName(dev) + "\n";
-       body += "Total output(s): " + gItoa(kernelAudio::getMaxOutChans(dev)) + "\n";
-       body += "Total intput(s): " + gItoa(kernelAudio::getMaxInChans(dev)) + "\n";
-       body += "Duplex channel(s): " + gItoa(kernelAudio::getDuplexChans(dev)) + "\n";
-       body += "Default output: " + string(kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n";
-       body += "Default input: " + string(kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n";
+       body  = "Device name: " + G_KernelAudio.getDeviceName(dev) + "\n";
+       body += "Total output(s): " + gu_itoa(G_KernelAudio.getMaxOutChans(dev)) + "\n";
+       body += "Total intput(s): " + gu_itoa(G_KernelAudio.getMaxInChans(dev)) + "\n";
+       body += "Duplex channel(s): " + gu_itoa(G_KernelAudio.getDuplexChans(dev)) + "\n";
+       body += "Default output: " + string(G_KernelAudio.isDefaultOut(dev) ? "yes" : "no") + "\n";
+       body += "Default input: " + string(G_KernelAudio.isDefaultIn(dev) ? "yes" : "no") + "\n";
 
-       int totalFreq = kernelAudio::getTotalFreqs(dev);
-       body += "Supported frequencies: " + gItoa(totalFreq);
+       int totalFreq = G_KernelAudio.getTotalFreqs(dev);
+       body += "Supported frequencies: " + gu_itoa(totalFreq);
 
        for (int i=0; i<totalFreq; i++) {
                if (i % 6 == 0) {
                        body += "\n    ";  // add new line each 6 printed freqs AND on the first line (i % 0 != 0)
                        lines++;
                }
-               body += gItoa( kernelAudio::getFreq(dev, i)) + "  ";
+               body += gu_itoa( G_KernelAudio.getFreq(dev, i)) + "  ";
        }
 
        text->copy_label(body.c_str());
index 501edfe23dd7faa0dd49e1559704e02bc3df08c6..af5d55b19d6b6baa89b516b005b5da42f0c74c49 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_editor
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
-#include "../../utils/gui_utils.h"
-#include "../../glue/glue.h"
+#include "../../glue/channel.h"
 #include "../../core/waveFx.h"
 #include "../../core/conf.h"
+#include "../../core/const.h"
 #include "../../core/graphics.h"
-#include "../../core/mixerHandler.h"
-#include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
 #include "../../core/mixer.h"
 #include "../../core/wave.h"
+#include "../elems/channel.h"
 #include "../elems/ge_waveform.h"
 #include "../elems/ge_mixed.h"
-#include "../elems/ge_channel.h"
 #include "../elems/ge_waveTools.h"
-#include "../elems/ge_keyboard.h"
-#include "gd_editor.h"
-#include "gd_mainWindow.h"
 #include "gd_warnings.h"
+#include "gd_editor.h"
 
 
-extern Mixer         G_Mixer;
-extern gdMainWindow *mainWin;
-extern Conf          G_Conf;
+extern Mixer G_Mixer;
+extern Conf  G_Conf;
 
 
 gdEditor::gdEditor(SampleChannel *ch)
@@ -81,28 +76,28 @@ gdEditor::gdEditor(SampleChannel *ch)
 
   Fl_Group *tools = new Fl_Group(8, waveTools->y()+waveTools->h()+8, w()-16, 130);
   tools->begin();
-    volume        = new gDial (tools->x()+42,                    tools->y(), 20, 20, "Volume");
+    volume        = new gDial (tools->x()+50,                    tools->y(), 20, 20, "Volume");
     volumeNum     = new gInput(volume->x()+volume->w()+4,        tools->y(), 46, 20, "dB");
 
-    boost         = new gDial (volumeNum->x()+volumeNum->w()+80, tools->y(), 20, 20, "Boost");
-    boostNum      = new gInput(boost->x()+boost->w()+4,          tools->y(), 46, 20, "dB");
+    boost         = new gDial (volumeNum->x()+volumeNum->w()+108, tools->y(), 20, 20, "Boost");
+    boostNum      = new gInput(boost->x()+boost->w()+4,           tools->y(), 44, 20, "dB");
 
     normalize     = new gClick(boostNum->x()+boostNum->w()+54,   tools->y(), 70, 20, "Normalize");
     pan           = new gDial (normalize->x()+normalize->w()+40, tools->y(), 20, 20, "Pan");
     panNum        = new gInput(pan->x()+pan->w()+4,              tools->y(), 45, 20, "%");
 
-    pitch         = new gDial (tools->x()+42,                       volume->y()+volume->h()+4, 20, 20, "Pitch");
+    pitch         = new gDial (tools->x()+50,                       volume->y()+volume->h()+4, 20, 20, "Pitch");
     pitchNum      = new gInput(pitch->x()+pitch->w()+4,             volume->y()+volume->h()+4, 46, 20);
-    pitchToBar    = new gClick(pitchNum->x()+pitchNum->w()+4,       volume->y()+volume->h()+4, 46, 20, "To bar");
-    pitchToSong   = new gClick(pitchToBar->x()+pitchToBar->w()+4,   volume->y()+volume->h()+4, 46, 20, "To song");
-    pitchHalf     = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 21, 20, "÷");
-    pitchDouble   = new gClick(pitchHalf->x()+pitchHalf->w()+4,     volume->y()+volume->h()+4, 21, 20, "×");
+    pitchToBar    = new gClick(pitchNum->x()+pitchNum->w()+4,       volume->y()+volume->h()+4, 60, 20, "To bar");
+    pitchToSong   = new gClick(pitchToBar->x()+pitchToBar->w()+4,   volume->y()+volume->h()+4, 60, 20, "To song");
+    pitchHalf     = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 20, 20, "", divideOff_xpm, divideOn_xpm);
+    pitchDouble   = new gClick(pitchHalf->x()+pitchHalf->w()+4,     volume->y()+volume->h()+4, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm);
     pitchReset    = new gClick(pitchDouble->x()+pitchDouble->w()+4, volume->y()+volume->h()+4, 46, 20, "Reset");
     reload        = new gClick(pitchReset->x()+pitchReset->w()+4,   volume->y()+volume->h()+4, 70, 20, "Reload");
 
-    chanStart     = new gInput(tools->x()+52,                    pitch->y()+pitch->h()+4, 60, 20, "Start");
-    chanEnd       = new gInput(chanStart->x()+chanStart->w()+40, pitch->y()+pitch->h()+4, 60, 20, "End");
-    resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4,      pitch->y()+pitch->h()+4, 46, 20, "Reset");
+    chanStart     = new gInput(tools->x()+60,                   pitch->y()+pitch->h()+4, 60, 20, "Range");
+    chanEnd       = new gInput(chanStart->x()+chanStart->w()+4, pitch->y()+pitch->h()+4, 60, 20, "");
+    resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4,     pitch->y()+pitch->h()+4, 60, 20, "Reset");
 
   tools->end();
   tools->resizable(new gBox(panNum->x()+panNum->w()+4, tools->y(), 80, tools->h()));
@@ -202,7 +197,7 @@ gdEditor::gdEditor(SampleChannel *ch)
 
   if (ch->panRight < 1.0f) {
     char buf[8];
-    sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100));
+    sprintf(buf, "%d L", (int) std::abs((ch->panRight * 100.0f) - 100));
     pan->value(ch->panRight);
     panNum->value(buf);
   }
@@ -212,7 +207,7 @@ gdEditor::gdEditor(SampleChannel *ch)
   }
   else {
     char buf[8];
-    sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100));
+    sprintf(buf, "%d R", (int) std::abs((ch->panLeft * 100.0f) - 100));
     pan->value(2.0f - ch->panLeft);
     panNum->value(buf);
   }
@@ -231,7 +226,7 @@ gdEditor::gdEditor(SampleChannel *ch)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 gdEditor::~gdEditor()
@@ -245,7 +240,7 @@ gdEditor::~gdEditor()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::cb_setChanPos      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setChanPos(); }
@@ -270,7 +265,7 @@ void gdEditor::cb_changeGrid      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb
 void gdEditor::cb_enableSnap      (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_enableSnap(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_enableSnap()
@@ -279,7 +274,7 @@ void gdEditor::__cb_enableSnap()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitchToBar()
@@ -288,7 +283,7 @@ void gdEditor::__cb_setPitchToBar()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitchToSong()
@@ -297,7 +292,7 @@ void gdEditor::__cb_setPitchToSong()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_resetPitch()
@@ -306,7 +301,7 @@ void gdEditor::__cb_resetPitch()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setChanPos()
@@ -321,7 +316,7 @@ void gdEditor::__cb_setChanPos()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_resetStartEnd()
@@ -330,7 +325,7 @@ void gdEditor::__cb_resetStartEnd()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setVolume()
@@ -339,7 +334,7 @@ void gdEditor::__cb_setVolume()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setVolumeNum()
@@ -348,7 +343,7 @@ void gdEditor::__cb_setVolumeNum()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setBoost()
@@ -362,7 +357,7 @@ void gdEditor::__cb_setBoost()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setBoostNum()
@@ -372,7 +367,7 @@ void gdEditor::__cb_setBoostNum()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_normalize()
@@ -390,7 +385,7 @@ void gdEditor::__cb_normalize()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_panning()
@@ -399,7 +394,7 @@ void gdEditor::__cb_panning()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_reload()
@@ -426,7 +421,7 @@ void gdEditor::__cb_reload()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitch()
@@ -435,7 +430,7 @@ void gdEditor::__cb_setPitch()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitchNum()
@@ -444,7 +439,7 @@ void gdEditor::__cb_setPitchNum()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitchHalf()
@@ -453,7 +448,7 @@ void gdEditor::__cb_setPitchHalf()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_setPitchDouble()
@@ -462,7 +457,7 @@ void gdEditor::__cb_setPitchDouble()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_zoomIn()
@@ -472,7 +467,7 @@ void gdEditor::__cb_zoomIn()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_zoomOut()
@@ -482,7 +477,7 @@ void gdEditor::__cb_zoomOut()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdEditor::__cb_changeGrid()
index cd7b9aeffbd1c484a5f7995bd9643f320641155b..c9ffe742dc33e1e863ae299ac924650b0c4c68ed 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_editor
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
+
 
 #ifndef GD_EDITOR_H
 #define GD_EDITOR_H
 
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <math.h>
-#include "../elems/ge_window.h"
 
+#include "../elems/ge_window.h"
 
-class gdEditor : public gWindow {
 
+class gdEditor : public gWindow
+{
 private:
 
        static void cb_setChanPos    (Fl_Widget *w, void *p);
@@ -113,4 +112,5 @@ public:
        class SampleChannel *ch;
 };
 
+
 #endif
index 47a8a54c092e19c21c96cbd782bb2591ec390998..508867b5c9feabe4af265dc24478ab9c8b60aa58 100644 (file)
@@ -27,7 +27,7 @@
  * -------------------------------------------------------------------------- */
 
 
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/conf.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
@@ -35,8 +35,8 @@
 #include "../../utils/log.h"
 #include "../elems/ge_keyboard.h"
 #include "../elems/ge_mixed.h"
-#include "../elems/ge_channel.h"
-#include "../elems/ge_channelButton.h"
+#include "../elems/channel.h"
+#include "../elems/channelButton.h"
 #include "gd_keyGrabber.h"
 #include "gd_config.h"
 #include "gd_mainWindow.h"
@@ -132,13 +132,13 @@ int gdKeyGrabber::handle(int e)
                            && x != FL_End
                            && x != ' ')
                        {
-                               gLog("set key '%c' (%d) for channel %d\n", x, x, ch->index);
+                               gu_log("set key '%c' (%d) for channel %d\n", x, x, ch->index);
                                setButtonLabel(x);
                                updateText(x);
                                break;
                        }
                        else
-                               gLog("invalid key\n");
+                               gu_log("invalid key\n");
                }
        }
        return(ret);
index b2012c20ab75519459677dedbdc313ce05029a97..dba57641aa4bc9be0974b2238b57e3968cdb3116 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_mainWindow
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifdef __linux__
 #include "../../core/sampleChannel.h"
 #include "../../core/init.h"
 #include "../../core/patch_DEPR_.h"
+#include "../../core/patch.h"
 #include "../../core/conf.h"
 #include "../../core/pluginHost.h"
-#include "../../glue/glue.h"
+#include "../../glue/main.h"
 #include "../../glue/storage.h"
 #include "../elems/ge_keyboard.h"
 #include "gd_warnings.h"
@@ -60,7 +61,7 @@ extern Mixer                   G_Mixer;
 extern Patch_DEPR_   G_Patch_DEPR_;
 extern Patch         G_Patch;
 extern Conf                             G_Conf;
-extern gdMainWindow *mainWin;
+extern gdMainWindow *G_MainWin;
 extern bool                                     G_quit;
 extern bool                             G_audio_status;
 
@@ -76,7 +77,7 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg
        size_range(GUI_WIDTH, GUI_HEIGHT);
 
        menu       = new gMenu(8, -1);
-       inOut      = new gInOut(414, 8);
+       inOut      = new gInOut(412, 8);
        controller = new gController(8, 39);
        timing     = new gTiming(628, 44);
        beatMeter  = new gBeatMeter(100, 83, 609, 20);
@@ -117,13 +118,13 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { mainWin->__cb_endprogram(); }
+void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { G_MainWin->__cb_endprogram(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdMainWindow::__cb_endprogram()
@@ -136,28 +137,28 @@ void gdMainWindow::__cb_endprogram()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gInOut::gInOut(int x, int y)
-       : Fl_Group(x, y, 394, 20)
+       : Fl_Group(x, y, 396, 20)
 {
        begin();
 
 #if defined(WITH_VST)
        masterFxIn  = new gFxButton  (x, y, 20, 20, fxOff_xpm, fxOn_xpm);
        inVol               = new gDial      (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20);
-       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
-       inToOut     = new gClick     (inMeter->x()+inMeter->w()+4, y+5, 10, 10, "");
-       outMeter    = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+5, 140, 10);
+       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+4, 140, 12);
+       inToOut     = new gClick     (inMeter->x()+inMeter->w()+4, y+4, 12, 12, "", inputToOutputOff_xpm, inputToOutputOn_xpm);
+       outMeter    = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+4, 140, 12);
        outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
        masterFxOut = new gFxButton  (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm);
 #else
        inVol               = new gDial      (x+62, y, 20, 20);
-       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10);
-       outMeter    = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 10);
+       inMeter     = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 12);
+       outMeter    = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 12);
        outVol            = new gDial      (outMeter->x()+outMeter->w()+4, y, 20, 20);
 #endif
 
@@ -179,7 +180,7 @@ gInOut::gInOut(int x, int y)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gInOut::cb_outVol     (Fl_Widget *v, void *p)     { ((gInOut*)p)->__cb_outVol(); }
@@ -191,7 +192,7 @@ void gInOut::cb_inToOut    (Fl_Widget *v, void *p)    { ((gInOut*)p)->__cb_inToO
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gInOut::__cb_outVol()
@@ -200,7 +201,7 @@ void gInOut::__cb_outVol()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gInOut::__cb_inVol()
@@ -209,18 +210,18 @@ void gInOut::__cb_inVol()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 #ifdef WITH_VST
 void gInOut::__cb_masterFxOut()
 {
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST);
+       gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST);
 }
 
 void gInOut::__cb_masterFxIn()
 {
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST);
+       gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST);
 }
 
 void gInOut::__cb_inToOut()
@@ -230,7 +231,7 @@ void gInOut::__cb_inToOut()
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gInOut::refresh()
@@ -242,9 +243,9 @@ void gInOut::refresh()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gMenu::gMenu(int x, int y)
@@ -268,7 +269,7 @@ gMenu::gMenu(int x, int y)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); }
@@ -277,25 +278,25 @@ void gMenu::cb_file  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); }
 void gMenu::cb_edit  (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gMenu::__cb_about()
 {
-       gu_openSubWindow(mainWin, new gdAbout(), WID_ABOUT);
+       gu_openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gMenu::__cb_config()
 {
-       gu_openSubWindow(mainWin, new gdConfig(380, 370), WID_CONFIG);
+       gu_openSubWindow(G_MainWin, new gdConfig(380, 370), WID_CONFIG);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gMenu::__cb_file()
@@ -322,11 +323,11 @@ void gMenu::__cb_file()
 
        if (strcmp(m->label(), "Open patch or project...") == 0) {
                //gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH);
-               //gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               //gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
                gWindow *childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY,
                                G_Conf.browserW, G_Conf.browserH, "Load patch or project",
                                G_Conf.patchPath, glue_loadPatch, NULL);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
                return;
        }
        if (strcmp(m->label(), "Save patch...") == 0) {
@@ -336,24 +337,24 @@ void gMenu::__cb_file()
                gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY,
                                G_Conf.browserW, G_Conf.browserH, "Save patch",
                                G_Conf.patchPath, G_Patch.name, glue_savePatch, NULL);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
                return;
        }
        if (strcmp(m->label(), "Save project...") == 0) {
                gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY,
                                G_Conf.browserW, G_Conf.browserH, "Save project",
                                G_Conf.patchPath, G_Patch.name, glue_saveProject, NULL);
-               gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER);
+               gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
                return;
        }
        if (strcmp(m->label(), "Quit Giada") == 0) {
-               mainWin->do_callback();
+               G_MainWin->do_callback();
                return;
        }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gMenu::__cb_edit()
@@ -396,14 +397,14 @@ void gMenu::__cb_edit()
        if (strcmp(m->label(), "Clear all samples") == 0) {
                if (!gdConfirmWin("Warning", "Clear all samples: are you sure?"))
                        return;
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
+               G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
                glue_clearAllSamples();
                return;
        }
        if (strcmp(m->label(), "Clear all actions") == 0) {
                if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
                        return;
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
+               G_MainWin->delSubWindow(WID_ACTION_EDITOR);
                glue_clearAllRecs();
                return;
        }
@@ -415,19 +416,19 @@ void gMenu::__cb_edit()
                return;
        }
        if (strcmp(m->label(), "Remove empty columns") == 0) {
-               mainWin->keyboard->organizeColumns();
+               G_MainWin->keyboard->organizeColumns();
                return;
        }
        if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0);
+               gu_openSubWindow(G_MainWin, new gdMidiInputMaster(), 0);
                return;
        }
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gTiming::gTiming(int x, int y)
@@ -438,8 +439,8 @@ gTiming::gTiming(int x, int y)
        quantizer  = new gChoice(x, y, 40, 20, "", false);
        bpm        = new gClick (quantizer->x()+quantizer->w()+4,  y, 40, 20);
        meter      = new gClick (bpm->x()+bpm->w()+8,  y, 40, 20, "4/1");
-       multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", beatsMultiplyOff_xpm, beatsMultiplyOn_xpm);
-       divider    = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", beatsDivideOff_xpm, beatsDivideOn_xpm);
+       multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm);
+       divider    = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm);
 
        end();
 
@@ -464,7 +465,7 @@ gTiming::gTiming(int x, int y)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::cb_bpm       (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); }
@@ -474,25 +475,25 @@ void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multipl
 void gTiming::cb_divider   (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::__cb_bpm()
 {
-       gu_openSubWindow(mainWin, new gdBpmInput(bpm->label()), WID_BPM);
+       gu_openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::__cb_meter()
 {
-       gu_openSubWindow(mainWin, new gdBeatsInput(), WID_BEATS);
+       gu_openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::__cb_quantizer()
@@ -501,7 +502,7 @@ void gTiming::__cb_quantizer()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::__cb_multiplier()
@@ -510,7 +511,7 @@ void gTiming::__cb_multiplier()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::__cb_divider()
@@ -519,7 +520,7 @@ void gTiming::__cb_divider()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::setBpm(const char *v)
@@ -536,7 +537,7 @@ void gTiming::setBpm(float v)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTiming::setMeter(int beats, int bars)
index 7adc52d4c72bfdcf6d1e97a9839ddbdf79247f23..a0a048904b4f8f802c0ad91ddc7ca162d08042f0 100644 (file)
@@ -1,9 +1,9 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  * gd_mainWindow
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -23,7 +23,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef GD_MAINWINDOW_H
@@ -37,7 +37,7 @@
 #include "../elems/ge_controller.h"
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 class gdMainWindow : public gWindow
@@ -60,7 +60,7 @@ public:
 };
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 class gInOut : public Fl_Group
@@ -108,7 +108,7 @@ public:
 };
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 class gMenu : public Fl_Group
@@ -136,7 +136,7 @@ public:
 };
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 class gTiming : public Fl_Group
index ce7f4681413d3838c7bd986bf65257a14f4fb8cb..e713416866b3def94225de2edad186e5a37648db 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/kernelMidi.h"
 #include "../../core/conf.h"
+#include "../../core/const.h"
 #include "../../core/sampleChannel.h"
 #include "../../utils/log.h"
+#include "../../utils/string.h"
 #include "../elems/ge_mixed.h"
 #include "../elems/ge_midiIoTools.h"
 #include "gd_midiInput.h"
 
 
-extern Conf G_Conf;
+extern Conf       G_Conf;
+extern KernelMidi G_KernelMidi;
+
+
+using std::string;
 
 
 gdMidiInput::gdMidiInput(int w, int h, const char *title)
@@ -49,16 +55,18 @@ gdMidiInput::gdMidiInput(int w, int h, const char *title)
 /* -------------------------------------------------------------------------- */
 
 
-gdMidiInput::~gdMidiInput() {
-       kernelMidi::stopMidiLearn();
+gdMidiInput::~gdMidiInput()
+{
+       G_KernelMidi.stopMidiLearn();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInput::stopMidiLearn(gLearner *learner) {
-       kernelMidi::stopMidiLearn();
+void gdMidiInput::stopMidiLearn(gLearner *learner)
+{
+       G_KernelMidi.stopMidiLearn();
        learner->updateValue();
 }
 
@@ -66,17 +74,19 @@ void gdMidiInput::stopMidiLearn(gLearner *learner) {
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l)
+{
        *param = msg;
        stopMidiLearn(l);
-       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+       gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInput::cb_learn(uint32_t msg, void *d) {
+void gdMidiInput::cb_learn(uint32_t msg, void *d)
+{
        cbData *data = (cbData*) d;
        gdMidiInput   *window  = (gdMidiInput*) data->window;
        gLearner      *learner = data->learner;
@@ -95,7 +105,8 @@ void gdMidiInput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiInput*)p)->__cb_clo
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInput::__cb_close() {
+void gdMidiInput::__cb_close()
+{
        do_callback();
 }
 
@@ -106,12 +117,11 @@ void gdMidiInput::__cb_close() {
 
 
 gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
-       :       gdMidiInput(300, 206, "MIDI Input Setup"),
+       :       gdMidiInput(300, 230, "MIDI Input Setup"),
                ch(ch)
 {
-       char title[64];
-       sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1);
-       label(title);
+  string title = "MIDI Input Setup (channel " + gu_itoa(ch->index+1) + ")";
+       label(title.c_str());
 
        set_modal();
 
@@ -119,16 +129,17 @@ gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
        new gLearner(8,  30, w()-16, "key press",   cb_learn, &ch->midiInKeyPress);
        new gLearner(8,  54, w()-16, "key release", cb_learn, &ch->midiInKeyRel);
        new gLearner(8,  78, w()-16, "key kill",    cb_learn, &ch->midiInKill);
-       new gLearner(8, 102, w()-16, "mute",        cb_learn, &ch->midiInMute);
-       new gLearner(8, 126, w()-16, "solo",        cb_learn, &ch->midiInSolo);
-       new gLearner(8, 150, w()-16, "volume",      cb_learn, &ch->midiInVolume);
-       int yy = 178;
+       new gLearner(8, 102, w()-16, "arm",         cb_learn, &ch->midiInArm);
+       new gLearner(8, 126, w()-16, "mute",        cb_learn, &ch->midiInMute);
+       new gLearner(8, 150, w()-16, "solo",        cb_learn, &ch->midiInSolo);
+       new gLearner(8, 174, w()-16, "volume",      cb_learn, &ch->midiInVolume);
+       int yy = 202;
 
        if (ch->type == CHANNEL_SAMPLE) {
-               size(300, 254);
-               new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
-               new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
-               yy = 226;
+               size(300, 278);
+               new gLearner(8, 198, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
+               new gLearner(8, 222, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
+               yy = 250;
        }
 
        ok = new gButton(w()-88, yy, 80, 20, "Close");
@@ -151,7 +162,8 @@ void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiInputChanne
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputChannel::__cb_enable() {
+void gdMidiInputChannel::__cb_enable()
+{
        ch->midiIn = enable->value();
 }
 
index 0ade1937747f17b87ae5070f00e4200704fe69d9..eb236e7fae992d93df8e6f07643f8c8e76109ff6 100644 (file)
 #define GD_MIDI_INPUT_H
 
 
-#include "../../core/kernelMidi.h"
-#include "../../utils/utils.h"
 #include "../elems/ge_window.h"
-#include "../elems/ge_mixed.h"
 
 
 class gdMidiInput : public gWindow
 {
 protected:
 
-       gClick *ok;
+       class gClick *ok;
 
        void stopMidiLearn(class gLearner *l);
 
@@ -70,8 +67,7 @@ private:
 
        class Channel *ch;
 
-       gCheck *enable;
-
+       class gCheck *enable;
 
        //gVector <gLearner *> items; for future use, with vst parameters
 
index 69aea2ccf2fbab807393d44d3dab87d5c5c7e918..5b2be1f248cab42d2b096f169e05a6f89643911a 100644 (file)
 #include "../../core/sampleChannel.h"
 #include "../../core/conf.h"
 #include "../../core/midiChannel.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
+#include "../../utils/log.h"
 #include "../elems/ge_mixed.h"
-#include "../elems/ge_channel.h"
+#include "../elems/channel.h"
 #include "../elems/ge_midiIoTools.h"
 #include "../elems/ge_keyboard.h"
 #include "gd_midiOutput.h"
 
 
-extern Conf    G_Conf;
+extern Conf          G_Conf;
+extern KernelMidi G_KernelMidi;
 
 
 gdMidiOutput::gdMidiOutput(int w, int h)
-       //: gWindow(300, 64, "Midi Output Setup")
        : gWindow(w, h, "Midi Output Setup")
 {
 }
@@ -52,8 +53,9 @@ gdMidiOutput::gdMidiOutput(int w, int h)
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutput::stopMidiLearn(gLearner *learner) {
-       kernelMidi::stopMidiLearn();
+void gdMidiOutput::stopMidiLearn(gLearner *learner)
+{
+       G_KernelMidi.stopMidiLearn();
        learner->updateValue();
 }
 
@@ -61,17 +63,19 @@ void gdMidiOutput::stopMidiLearn(gLearner *learner) {
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l)
+{
        *param = msg;
        stopMidiLearn(l);
-       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+       gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutput::cb_learn(uint32_t msg, void *d) {
+void gdMidiOutput::cb_learn(uint32_t msg, void *d)
+{
        cbData *data = (cbData*) d;
        gdMidiOutput  *window  = (gdMidiOutput*) data->window;
        gLearner      *learner = data->learner;
@@ -90,7 +94,8 @@ void gdMidiOutput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiOutput*)p)->__cb_c
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutput::__cb_close() {
+void gdMidiOutput::__cb_close()
+{
        do_callback();
 }
 
@@ -98,7 +103,8 @@ void gdMidiOutput::__cb_close() {
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p)  {
+void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p)
+{
        ((gdMidiOutput*)p)->__cb_enableLightning();
 }
 
@@ -190,7 +196,8 @@ void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutp
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutputMidiCh::__cb_enableChanList() {
+void gdMidiOutputMidiCh::__cb_enableChanList()
+{
        enableOut->value() ? chanListOut->activate() : chanListOut->deactivate();
 }
 
@@ -198,7 +205,8 @@ void gdMidiOutputMidiCh::__cb_enableChanList() {
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutputMidiCh::__cb_close() {
+void gdMidiOutputMidiCh::__cb_close()
+{
        ch->midiOut     = enableOut->value();
        ch->midiOutChan = chanListOut->value();
        ch->midiOutL    = enableLightning->value();
@@ -243,7 +251,8 @@ void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampl
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiOutputSampleCh::__cb_close() {
+void gdMidiOutputSampleCh::__cb_close()
+{
        ch->midiOutL = enableLightning->value();
        do_callback();
 }
index c090caa8b9afa53db331bc07f61766a7455f3fe2..d86810867856a969932f2634a1aa29c25cba91af 100644 (file)
@@ -30,7 +30,7 @@
 #ifdef WITH_VST
 
 
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/channel.h"
 #include "../../core/mixer.h"
 #include "../../core/conf.h"
index 433284f76ed3fadc0346eef9b3b0c186a0db7443..003ca630674f47ab2e9a568da5a59e99fa7f6462 100644 (file)
 #ifdef WITH_VST
 
 
-#include "../../utils/gui_utils.h"
-#include "../../utils/utils.h"
+#include "../../utils/gui.h"
+#include "../../utils/fs.h"
 #include "../../core/conf.h"
+#include "../../core/const.h"
 #include "../../core/graphics.h"
 #include "../../core/pluginHost.h"
 #include "../../core/plugin.h"
 #include "../../core/mixer.h"
 #include "../../core/channel.h"
+#include "../../utils/log.h"
+#include "../../utils/string.h"
 #include "../elems/ge_mixed.h"
-#include "../elems/ge_channel.h"
+#include "../elems/channel.h"
 #include "gd_pluginList.h"
 #include "gd_pluginChooser.h"
 #include "gd_pluginWindow.h"
@@ -51,7 +54,7 @@
 extern Conf          G_Conf;
 extern Mixer         G_Mixer;
 extern PluginHost    G_PluginHost;
-extern gdMainWindow *mainWin;
+extern gdMainWindow *G_MainWin;
 
 
 using std::string;
@@ -86,7 +89,7 @@ gdPluginList::gdPluginList(int stackType, Channel *ch)
        if (stackType == PluginHost::MASTER_IN)
                label("Master In Plugins");
        else {
-    string l = "Channel " + gItoa(ch->index+1) + " Plugins";
+    string l = "Channel " + gu_itoa(ch->index+1) + " Plugins";
     copy_label(l.c_str());
        }
 
@@ -195,12 +198,12 @@ void gdPluginList::refreshList() {
   gdPluginListMaster */
 
        if (stackType == PluginHost::MASTER_OUT) {
-    mainWin->inOut->setMasterFxOutFull(
+    G_MainWin->inOut->setMasterFxOutFull(
                        G_PluginHost.countPlugins(stackType, ch) > 0);
   }
        else
        if (stackType == PluginHost::MASTER_IN) {
-    mainWin->inOut->setMasterFxInFull(
+    G_MainWin->inOut->setMasterFxInFull(
                        G_PluginHost.countPlugins(stackType, ch) > 0);
   }
        else {
@@ -340,13 +343,13 @@ void gdPlugin::__cb_openPluginWindow()
   gWindow *w;
   if (pPlugin->hasEditor()) {
     if (pPlugin->isEditorOpen()) {
-      gLog("[gdPlugin::__cb_openPluginWindow] plugin has editor but it's already visible\n");
+      gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor but it's already visible\n");
       return;
     }
 
     int pwid = pPlugin->getId()+1;
 
-    gLog("[gdPlugin::__cb_openPluginWindow] plugin has editor, open window id=%d\n", pwid);
+    gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor, open window id=%d\n", pwid);
 
     if (pParent->hasWindow(pwid))
       pParent->delSubWindow(pwid);
index cc4348a60e3d912b69c0687c23e1df793b9f7f63..0c0be5f3b8996e7a24ef66485fc8cb80f5c891c3 100644 (file)
@@ -31,7 +31,7 @@
 
 
 #include <FL/Fl_Scroll.H>
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/plugin.h"
 #include "../elems/ge_mixed.h"
 #include "gd_pluginWindow.h"
index b50b1f4a1a57e238aab3d466bae89d2804aef7b8..e8ba698345b42649b0b62ec2281e5b211edf9562 100644 (file)
@@ -31,7 +31,7 @@
 
 
 #include "../../utils/log.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/pluginHost.h"
 #include "../../core/plugin.h"
 #include "../../core/const.h"
@@ -57,7 +57,7 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
 
 #endif
 
-  gLog("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
+  gu_log("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
     (void*) this, (void*) fl_xid(this));
 
 #if defined(__APPLE__)
@@ -75,8 +75,6 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
   int pluginW = pPlugin->getEditorW();
   int pluginH = pPlugin->getEditorH();
 
-  printf("w=%d h=%d\n", Fl::w(), Fl::h());
-
   resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH);
 
   Fl::add_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this);
@@ -100,7 +98,7 @@ void gdPluginWindowGUI::__cb_close()
 {
   Fl::remove_timeout(cb_refresh);
   pPlugin->closeEditor();
-  gLog("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this);
+  gu_log("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this);
 }
 
 
@@ -109,7 +107,7 @@ void gdPluginWindowGUI::__cb_close()
 
 void gdPluginWindowGUI::__cb_refresh()
 {
-  //gLog("[gdPluginWindowGUI::__cb_refresh] refresh!\n");
+  //gu_log("[gdPluginWindowGUI::__cb_refresh] refresh!\n");
   G_PluginHost.runDispatchLoop();
   Fl::repeat_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this);
 }
index c2350cf329670b540367f0370dbe8481083361a8..13d3b4e5a6bbd924bf38719e183a1f0471a27b75 100644 (file)
@@ -33,7 +33,7 @@
 #include <FL/Fl_Window.H>
 #include <FL/Fl_Box.H>
 #include "../elems/ge_mixed.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 
 
 void gdAlert(const char *c);
diff --git a/src/gui/elems/actionEditor.cpp b/src/gui/elems/actionEditor.cpp
new file mode 100644 (file)
index 0000000..4a88413
--- /dev/null
@@ -0,0 +1,679 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../glue/main.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "ge_keyboard.h"
+#include "actionEditor.h"
+
+
+extern gdMainWindow *G_MainWin;
+extern Mixer         G_Mixer;
+extern Conf             G_Conf;
+extern Recorder      G_Recorder;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+geActionEditor::geActionEditor(int x, int y, gdActionEditor *pParent, SampleChannel *ch)
+  : geBaseActionEditor(x, y, 200, 40, pParent),
+    ch                (ch),
+    selected          (NULL)
+{
+       size(pParent->totalWidth, h());
+
+       /* add actions when the window opens. Their position is zoom-based;
+        * each frame is / 2 because we don't care about stereo infos. */
+
+       for (unsigned i=0; i<G_Recorder.frames.size(); i++) {
+               for (unsigned j=0; j<G_Recorder.global.at(i).size(); j++) {
+
+                 Recorder::action *action = G_Recorder.global.at(i).at(j);
+
+      /* Don't show actions:
+      - that don't belong to the displayed channel (!= pParent->chan->index);
+      - that are covered by the grey area (> G_Mixer.totalFrames);
+      - of type ACTION_KILLCHAN in a SINGLE_PRESS channel. They cannot be
+        recorded in such mode, but they can exist if you change from another
+        mode to singlepress;
+      - of type ACTION_KEYREL in a SINGLE_PRESS channel. It's up to gAction to
+        find the other piece (namely frame_b)
+      - not of types ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN */
+
+      if ((action->chan != pParent->chan->index)                            ||
+          (G_Recorder.frames.at(i) > G_Mixer.totalFrames)                    ||
+          (action->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS)     ||
+          (action->type == ACTION_KEYREL && ch->mode == SINGLE_PRESS)       ||
+          (action->type & ~(ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN))
+      )
+        continue;
+
+                       int ax = x + (action->frame / pParent->zoom);
+                       gAction *a = new gAction(
+                                       ax,               // x
+                                       y + 4,            // y
+                                       h() - 8,          // h
+                                       action->frame,    // frame_a
+                                       i,                // n. of recordings
+                                       pParent,          // pointer to the pParent window
+                                       ch,               // pointer to SampleChannel
+                                       false,            // record = false: don't record it, we are just displaying it!
+                                       action->type);    // type of action
+                       add(a);
+               }
+       }
+       end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gAction *geActionEditor::getSelectedAction()
+{
+       for (int i=0; i<children(); i++) {
+               int action_x  = ((gAction*)child(i))->x();
+               int action_w  = ((gAction*)child(i))->w();
+               if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w)
+                       return (gAction*)child(i);
+       }
+       return NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geActionEditor::updateActions()
+{
+       /* when zooming, don't delete and re-add actions, just MOVE them. This
+        * function shifts the action by a zoom factor. Those singlepress are
+        * stretched, as well */
+
+       gAction *a;
+       for (int i=0; i<children(); i++) {
+
+               a = (gAction*)child(i);
+               int newX = x() + (a->frame_a / pParent->zoom);
+
+               if (ch->mode == SINGLE_PRESS) {
+                       int newW = ((a->frame_b - a->frame_a) / pParent->zoom);
+                       if (newW < gAction::MIN_WIDTH)
+                               newW = gAction::MIN_WIDTH;
+                       a->resize(newX, a->y(), newW, a->h());
+               }
+               else
+                       a->resize(newX, a->y(), gAction::MIN_WIDTH, a->h());
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geActionEditor::draw()
+{
+       /* draw basic boundaries (+ beat bars) and hide the unused area. Then
+        * draw the children (the actions) */
+
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       if (active())
+               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
+       else
+               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
+
+       draw_children();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geActionEditor::handle(int e)
+{
+       int ret = Fl_Group::handle(e);
+
+       /* do nothing if the widget is deactivated. It could happen for loopmode
+        * channels */
+
+       if (!active())
+               return 1;
+
+       switch (e) {
+
+               case FL_DRAG: {
+
+      if (selected == NULL) {  // if you drag an empty area
+        ret = 1;
+        break;
+      }
+
+                       /* if onLeftEdge o onRightEdge are true it means that you're resizing
+                        * an action. Otherwise move the widget. */
+
+                       if (selected->onLeftEdge || selected->onRightEdge) {
+
+                               /* some checks: a) cannot resize an action < N pixels, b) no beyond zero,
+                                * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */
+
+                               if (selected->onRightEdge) {
+
+                                       int aw = Fl::event_x()-selected->x();
+                                       int ah = selected->h();
+
+                                       if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH)
+                                               aw = gAction::MIN_WIDTH;
+                                       else
+                                       if (Fl::event_x() > pParent->coverX)
+                                               aw = pParent->coverX-selected->x();
+
+                                       selected->size(aw, ah);
+                               }
+                               else {
+
+                                       int ax = Fl::event_x();
+                                       int ay = selected->y();
+                                       int aw = selected->x()-Fl::event_x()+selected->w();
+                                       int ah = selected->h();
+
+                                       if (Fl::event_x() < x()) {
+                                               ax = x();
+                                               aw = selected->w()+selected->x()-x();
+                                       }
+                                       else
+                                       if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) {
+                                               ax = selected->x()+selected->w()-gAction::MIN_WIDTH;
+                                               aw = gAction::MIN_WIDTH;
+                                       }
+                                       selected->resize(ax, ay, aw, ah);
+                               }
+                       }
+
+      /* move the widget around */
+
+                       else {
+                               int real_x = Fl::event_x() - actionPickPoint;
+                               if (real_x < x())                                  // don't go beyond the left border
+                                       selected->position(x(), selected->y());
+                               else
+                               if (real_x+selected->w() > pParent->coverX+x())         // don't go beyond the right border
+                                       selected->position(pParent->coverX+x()-selected->w(), selected->y());
+                               else {
+                                       if (pParent->gridTool->isOn()) {
+                                               int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1;
+                                               selected->position(snpx, selected->y());
+                                       }
+                                       else
+                                               selected->position(real_x, selected->y());
+                               }
+                       }
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH:   {
+
+                       if (Fl::event_button1()) {
+
+                               /* avoid at all costs two overlapping actions. We use 'selected' because
+                                * the selected action can be reused in FL_DRAG, in case you want to move
+                                * it. */
+
+                               selected = getSelectedAction();
+
+                               if (selected == NULL) {
+
+                                       /* avoid click on grey area */
+
+                                       if (Fl::event_x() >= pParent->coverX) {
+                                               ret = 1;
+                                               break;
+                                       }
+
+                                       /* snap function, if enabled */
+
+                                       int ax = Fl::event_x();
+                                       int fx = (ax - x()) * pParent->zoom;
+                                       if (pParent->gridTool->isOn()) {
+                                               ax = pParent->gridTool->getSnapPoint(ax-x()) + x() -1;
+                                               fx = pParent->gridTool->getSnapFrame(ax-x());
+
+                                               /* with snap=on an action can fall onto another */
+
+                                               if (actionCollides(fx)) {
+                                                       ret = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       gAction *a = new gAction(
+                                                       ax,                                   // x
+                                                       y()+4,                                // y
+                                                       h()-8,                                // h
+                                                       fx,                                                                                                                                             // frame_a
+                                                       G_Recorder.frames.size()-1,            // n. of actions recorded
+                                                       pParent,                              // pParent window pointer
+                                                       ch,                                   // pointer to SampleChannel
+                                                       true,                                 // record = true: record it!
+                                                       pParent->getActionType());            // type of action
+                                       add(a);
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)ch->guiChannel); // mainWindow update
+                                       redraw();
+                                       ret = 1;
+                               }
+                               else {
+                                       actionOriginalX = selected->x();
+                                       actionOriginalW = selected->w();
+                                       actionPickPoint = Fl::event_x() - selected->x();
+                                       ret = 1;   // for dragging
+                               }
+                       }
+                       else
+                       if (Fl::event_button3()) {
+                               gAction *a = getSelectedAction();
+                               if (a != NULL) {
+                                       a->delAction();
+                                       remove(a);
+                                       delete a;
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel);
+                                       redraw();
+                                       ret = 1;
+                               }
+                       }
+                       break;
+               }
+               case FL_RELEASE: {
+
+                       if (selected == NULL) {
+                               ret = 1;
+                               break;
+                       }
+
+                       /* noChanges = true when you click on an action without doing anything
+                        * (dragging or moving it). */
+
+                       bool noChanges = false;
+                       if (actionOriginalX == selected->x())
+                               noChanges = true;
+                       if (ch->mode == SINGLE_PRESS &&
+                                       actionOriginalX+actionOriginalW != selected->x()+selected->w())
+                               noChanges = false;
+
+                       if (noChanges) {
+                               ret = 1;
+                               selected = NULL;
+                               break;
+                       }
+
+                       /* step 1: check if the action doesn't overlap with another one.
+                        * In case of overlap the moved action returns to the original X
+                        * value ("actionOriginalX"). */
+
+                       bool overlap = false;
+                       for (int i=0; i<children() && !overlap; i++) {
+
+                               /* never check against itself. */
+
+                               if ((gAction*)child(i) == selected)
+                                       continue;
+
+                               int action_x  = ((gAction*)child(i))->x();
+                               int action_w  = ((gAction*)child(i))->w();
+                               if (ch->mode == SINGLE_PRESS) {
+
+                                       /* when 2 segments overlap?
+                                        * start = the highest value between the two starting points
+                                        * end   = the lowest value between the two ending points
+                                        * if start < end then there's an overlap of end-start pixels. */
+
+                                        int start = action_x >= selected->x() ? action_x : selected->x();
+                                        int end   = action_x+action_w < selected->x()+selected->w() ? action_x+action_w : selected->x()+selected->w();
+                                        if (start < end) {
+                                               selected->resize(actionOriginalX, selected->y(), actionOriginalW, selected->h());
+                                               redraw();
+                                               overlap = true;   // one overlap: stop checking
+                                       }
+                               }
+                               else {
+                                       if (selected->x() == action_x) {
+                                               selected->position(actionOriginalX, selected->y());
+                                               redraw();
+                                               overlap = true;   // one overlap: stop checking
+                                       }
+                               }
+                       }
+
+                       /* step 2: no overlap? then update the coordinates of the action, ie
+                        * delete the previous rec and create a new one.
+                        * Anyway the selected action becomes NULL, because when you release
+                        * the mouse button the dragging process ends. */
+
+                       if (!overlap) {
+                               if (pParent->gridTool->isOn()) {
+                                       int f = pParent->gridTool->getSnapFrame(selected->absx());
+                                       selected->moveAction(f);
+                               }
+                               else
+                                       selected->moveAction();
+                       }
+                       selected = NULL;
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool geActionEditor::actionCollides(int frame)
+{
+       /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't
+        * overlap the head (frame) of the new one. First the general case, yet. */
+
+       bool collision = false;
+
+       for (int i=0; i<children() && !collision; i++)
+               if (((gAction*) child(i))->frame_a == frame)
+                       collision = true;
+
+       if (ch->mode == SINGLE_PRESS) {
+               for (int i=0; i<children() && !collision; i++) {
+                       gAction *c = ((gAction*) child(i));
+                       if (frame <= c->frame_b && frame >= c->frame_a)
+                               collision = true;
+               }
+       }
+
+       return collision;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+/** TODO - index is useless?
+ *  TODO - pass a record::action pointer and let gAction compute values */
+
+gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEditor *parent, SampleChannel *ch, bool record, char type)
+: Fl_Box     (X, Y, MIN_WIDTH, H),
+  selected   (false),
+  index      (index),
+  parent     (parent),
+  ch         (ch),
+  type       (type),
+  frame_a    (frame_a),
+  onRightEdge(false),
+  onLeftEdge (false)
+{
+       /* bool 'record' defines how to understand the action.
+        * record = false: don't record it, just show it. It happens when you
+        * open the editor with some actions to be shown.
+        *
+        * record = true: record it AND show it. It happens when you click on
+        * an empty area in order to add a new actions. First you record it
+        * (addAction()) then you show it (FLTK::Draw()) */
+
+       if (record)
+               addAction();
+
+       /* in order to show a singlepress action we must compute the frame_b. We
+        * do that after the possible recording, otherwise we don't know which
+        * key_release is associated. */
+
+       if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) {
+               Recorder::action *a2 = NULL;
+               G_Recorder.getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2);
+               if (a2) {
+                       frame_b = a2->frame;
+                       w((frame_b - frame_a)/parent->zoom);
+               }
+               else
+                       gu_log("[geActionEditor] frame_b not found! [%d:???]\n", frame_a);
+
+       /* a singlepress action narrower than 8 pixel is useless. So check it.
+        * Warning: if an action is 8 px narrow, it has no body space to drag
+        * it. It's up to the user to zoom in and drag it. */
+
+               if (w() < MIN_WIDTH)
+                       size(MIN_WIDTH, h());
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gAction::draw()
+{
+       int color;
+       if (selected)  /// && geActionEditor !disabled
+               color = COLOR_BD_1;
+       else
+               color = COLOR_BG_2;
+
+       if (ch->mode == SINGLE_PRESS) {
+               fl_rectf(x(), y(), w(), h(), (Fl_Color) color);
+       }
+       else {
+               if (type == ACTION_KILLCHAN)
+                       fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
+               else {
+                       fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
+                       if (type == ACTION_KEYPRESS)
+                               fl_rectf(x()+3, y()+h()-11, 2, 8, COLOR_BD_0);
+                       else
+                       if  (type == ACTION_KEYREL)
+                               fl_rectf(x()+3, y()+3, 2, 8, COLOR_BD_0);
+               }
+       }
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gAction::handle(int e)
+{
+       /* ret = 0 sends the event to the parent window. */
+
+       int ret = 0;
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       selected = true;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+               case FL_LEAVE: {
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       selected = false;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+               case FL_MOVE: {
+
+                       /* handling of the two margins, left & right. 4 pixels are good enough */
+
+                       if (ch->mode == SINGLE_PRESS) {
+                               onLeftEdge  = false;
+                               onRightEdge = false;
+                               if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
+                                       onLeftEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                               if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
+                                       onRightEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       }
+               }
+       }
+
+       return ret;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gAction::addAction()
+{
+       /* always check frame parity */
+
+       if (frame_a % 2 != 0)
+               frame_a++;
+
+       /* anatomy of an action
+        * ____[#######]_____ (a) is the left margin, ACTION_KEYPRESS. (b) is
+        *     a       b      the right margin, the ACTION_KEYREL. This is the
+        * theory behind the singleshot.press actions; for any other kind the
+        * (b) is just a graphical and meaningless point. */
+
+       if (ch->mode == SINGLE_PRESS) {
+               G_Recorder.rec(parent->chan->index, ACTION_KEYPRESS, frame_a);
+               G_Recorder.rec(parent->chan->index, ACTION_KEYREL, frame_a+4096);
+               //gu_log("action added, [%d, %d]\n", frame_a, frame_a+4096);
+       }
+       else {
+               G_Recorder.rec(parent->chan->index, parent->getActionType(), frame_a);
+               //gu_log("action added, [%d]\n", frame_a);
+       }
+
+       G_Recorder.sortActions();
+
+       index++; // important!
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gAction::delAction()
+{
+       /* if SINGLE_PRESS you must delete both the keypress and the keyrelease
+        * actions. */
+
+       if (ch->mode == SINGLE_PRESS) {
+               G_Recorder.deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false);
+               G_Recorder.deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false);
+       }
+       else
+               G_Recorder.deleteAction(parent->chan->index, frame_a, type, false);
+
+       /* restore the initial cursor shape, in case you delete an action and
+        * the double arrow (for resizing) is displayed */
+
+       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gAction::moveAction(int frame_a)
+{
+       /* easy one: delete previous action and record the new ones. As usual,
+        * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame
+        * value. */
+
+       delAction();
+
+       if (frame_a != -1)
+               this->frame_a = frame_a;
+       else
+               this->frame_a = xToFrame_a();
+
+
+       /* always check frame parity */
+
+       if (this->frame_a % 2 != 0)
+               this->frame_a++;
+
+       G_Recorder.rec(parent->chan->index, type, this->frame_a);
+
+       if (ch->mode == SINGLE_PRESS) {
+               frame_b = xToFrame_b();
+               G_Recorder.rec(parent->chan->index, ACTION_KEYREL, frame_b);
+       }
+
+       G_Recorder.sortActions();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gAction::absx()
+{
+       return x() - parent->ac->x();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gAction::xToFrame_a()
+{
+       return (absx()) * parent->zoom;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gAction::xToFrame_b()
+{
+       return (absx() + w()) * parent->zoom;
+}
diff --git a/src/gui/elems/actionEditor.h b/src/gui/elems/actionEditor.h
new file mode 100644 (file)
index 0000000..56f0ce8
--- /dev/null
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_ACTIONCHANNEL_H
+#define GE_ACTIONCHANNEL_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Box.H>
+#include "../../utils/gui.h"
+#include "../../core/mixer.h"
+#include "../../core/recorder.h"
+#include "baseActionEditor.h"
+
+
+class gAction : public Fl_Box
+{
+private:
+
+       bool                  selected;
+       unsigned              index;
+  class gdActionEditor *parent;   // pointer to parent (gActionEditor)
+       class SampleChannel  *ch;
+  char                  type;     // type of action
+
+public:
+
+       gAction(int x, int y, int h, int frame_a, unsigned index,
+                                 gdActionEditor *parent, class SampleChannel *ch, bool record,
+                           char type);
+       void draw();
+       int  handle(int e);
+       void addAction();
+       void delAction();
+
+       /* moveAction
+        * shift the action on the x-axis and update Recorder. If frame_a != -1
+        * use the new frame in input (used while snapping) */
+
+       void moveAction(int frame_a=-1);
+
+       /* absx
+        * x() is relative to scrolling position. absx() returns the absolute
+        * x value of the action, from the leftmost edge. */
+
+       int  absx();
+
+       /* xToFrame_a,b
+        * return the real frames of x() position */
+
+       int xToFrame_a();
+       int xToFrame_b();
+
+       int frame_a;  // initial frame (KEYPRESS for singlemode.press)
+       int frame_b;  // terminal frame (KEYREL for singlemode.press, null for others)
+
+       bool onRightEdge;
+       bool onLeftEdge;
+
+       static const int MIN_WIDTH = 8;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class geActionEditor : public geBaseActionEditor
+{
+
+private:
+
+       class SampleChannel *ch;
+
+       /* getSelectedAction
+        * get the action under the mouse. NULL if nothing found. */
+
+       gAction *getSelectedAction();
+
+       /* selected
+        * pointer to the selected action. Useful when dragging around. */
+
+       gAction *selected;
+
+       /* actionOriginalX, actionOriginalW
+        * x and w of the action, when moved. Useful for checking if the action
+        * overlaps another one: in that case the moved action returns to
+        * actionOriginalX (and to actionOriginalW if resized). */
+
+       int actionOriginalX;
+       int actionOriginalW;
+
+       /* actionPickPoint
+        * the precise x point in which the action has been picked with the mouse,
+        * before a dragging action. */
+
+       int actionPickPoint;
+
+
+       /* actionCollides
+        * true if an action collides with another. Used while adding new points
+        * with snap active.*/
+
+       bool actionCollides(int frame);
+
+public:
+
+       geActionEditor(int x, int y, gdActionEditor *pParent, class SampleChannel *ch);
+       void draw();
+       int  handle(int e);
+       void updateActions();
+};
+
+
+#endif
diff --git a/src/gui/elems/baseActionEditor.cpp b/src/gui/elems/baseActionEditor.cpp
new file mode 100644 (file)
index 0000000..bc7a412
--- /dev/null
@@ -0,0 +1,102 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionWidget
+ *
+ * pParent class of any widget inside the action editor.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/mixer.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "baseActionEditor.h"
+#include "ge_mixed.h"
+
+
+extern Mixer G_Mixer;
+
+
+geBaseActionEditor::geBaseActionEditor(int x, int y, int w, int h,
+       gdActionEditor *pParent)
+       :       Fl_Group(x, y, w, h), pParent(pParent) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+geBaseActionEditor::~geBaseActionEditor() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geBaseActionEditor::baseDraw(bool clear) {
+
+       /* clear the screen */
+
+       if (clear)
+               fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
+
+       /* draw the container */
+
+       fl_color(COLOR_BD_0);
+       fl_rect(x(), y(), w(), h());
+
+       /* grid drawing, if > 1 */
+
+       if (pParent->gridTool->getValue() > 1) {
+
+               fl_color(fl_rgb_color(54, 54, 54));
+               fl_line_style(FL_DASH, 0, NULL);
+
+               for (int i=0; i<(int) pParent->gridTool->points.size(); i++) {
+                       int px = pParent->gridTool->points.at(i)+x()-1;
+                       fl_line(px, y()+1, px, y()+h()-2);
+               }
+               fl_line_style(0);
+       }
+
+       /* bars and beats drawing */
+
+       fl_color(COLOR_BD_0);
+       for (int i=0; i<(int) pParent->gridTool->beats.size(); i++) {
+               int px = pParent->gridTool->beats.at(i)+x()-1;
+               fl_line(px, y()+1, px, y()+h()-2);
+       }
+
+       fl_color(COLOR_BG_2);
+       for (int i=0; i<(int) pParent->gridTool->bars.size(); i++) {
+               int px = pParent->gridTool->bars.at(i)+x()-1;
+               fl_line(px, y()+1, px, y()+h()-2);
+       }
+
+       /* cover unused area. Avoid drawing cover if width == 0 (i.e. beats
+        * are 32) */
+
+       int coverWidth = pParent->totalWidth-pParent->coverX;
+       if (coverWidth != 0)
+               fl_rectf(pParent->coverX+x(), y()+1, coverWidth, h()-2, COLOR_BG_1);
+}
diff --git a/src/gui/elems/baseActionEditor.h b/src/gui/elems/baseActionEditor.h
new file mode 100644 (file)
index 0000000..49c74b1
--- /dev/null
@@ -0,0 +1,55 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_actionWidget
+ *
+ * parent class of any tool inside the action editor.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __GE_ACTIONWIDGET_H__
+#define __GE_ACTIONWIDGET_H__
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "../../core/const.h"
+
+
+class geBaseActionEditor : public Fl_Group
+{
+protected:
+
+       class gdActionEditor *pParent;
+       void  baseDraw(bool clear=true);
+
+public:
+
+       virtual void updateActions() = 0;
+
+       geBaseActionEditor(int x, int y, int w, int h, gdActionEditor *pParent);
+       ~geBaseActionEditor();
+};
+
+#endif
diff --git a/src/gui/elems/channel.cpp b/src/gui/elems/channel.cpp
new file mode 100644 (file)
index 0000000..a33f121
--- /dev/null
@@ -0,0 +1,243 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/patch_DEPR_.h"
+#include "../../core/graphics.h"
+#include "../../core/pluginHost.h"
+#include "../../utils/gui.h"
+#include "../../glue/channel.h"
+#include "../../glue/main.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_pluginList.h"
+#include "ge_column.h"
+#include "channelButton.h"
+#include "channel.h"
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Patch_DEPR_   G_Patch_DEPR_;
+extern gdMainWindow *G_MainWin;
+
+
+geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch)
+ : Fl_Group(X, Y, W, H, NULL),
+   ch      (ch),
+   type    (type)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::cb_arm(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_arm(); }
+void geChannel::cb_mute(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_mute(); }
+void geChannel::cb_solo(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_solo(); }
+void geChannel::cb_changeVol(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_changeVol(); }
+#ifdef WITH_VST
+void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_openFxWindow(); }
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::__cb_arm()
+{
+  glue_toggleArm(ch, true);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::__cb_mute()
+{
+       glue_setMute(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::__cb_solo()
+{
+       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::__cb_changeVol()
+{
+       glue_setChanVol(ch, vol->value());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+void geChannel::__cb_openFxWindow()
+{
+       gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
+}
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geChannel::keyPress(int e)
+{
+       return handleKey(e, ch->key);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+
+int geChannel::getColumnIndex()
+{
+       return ((gColumn*)parent())->getIndex();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::blink()
+{
+       if (gu_getBlinker() > 6)
+               mainButton->setPlayMode();
+       else
+    mainButton->setDefaultMode();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::setColorsByStatus(int playStatus, int recStatus)
+{
+  switch (playStatus) {
+    case STATUS_OFF:
+    case STATUS_EMPTY:
+               mainButton->setDefaultMode();
+      button->imgOn  = channelPlay_xpm;
+      button->imgOff = channelStop_xpm;
+      button->redraw();
+      break;
+    case STATUS_PLAY:
+      mainButton->setPlayMode();
+      button->imgOn  = channelStop_xpm;
+      button->imgOff = channelPlay_xpm;
+      button->redraw();
+      break;
+    case STATUS_WAIT:
+      blink();
+      break;
+    case STATUS_ENDING:
+      mainButton->setEndingMode();
+      break;
+  }
+
+  switch (recStatus) {
+    case REC_WAITING:
+      blink();
+      break;
+    case REC_ENDING:
+      mainButton->setEndingMode();
+      break;
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::packWidgets()
+{
+  /* Count visible widgets and resize mainButton according to how many widgets
+  are visible. */
+
+  int visibles = 0;
+  for (int i=0; i<children(); i++) {
+    child(i)->size(20, 20);  // also normalize widths
+    if (child(i)->visible())
+      visibles++;
+  }
+  mainButton->size(w() - ((visibles - 1) * (24)), 20);  // -1: exclude itself
+
+  /* Reposition everything else */
+
+  for (int i=1, p=0; i<children(); i++) {
+    if (!child(i)->visible())
+      continue;
+    for (int k=i-1; k>=0; k--) // Get the first visible item prior to i
+      if (child(k)->visible()) {
+        p = k;
+        break;
+      }
+    child(i)->position(child(p)->x() + child(p)->w() + 4, y());
+  }
+
+  init_sizes(); // Resets the internal array of widget sizes and positions
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geChannel::handleKey(int e, int key)
+{
+       int ret;
+       if (e == FL_KEYDOWN && button->value())                              // key already pressed! skip it
+               ret = 1;
+       else
+       if (Fl::event_key() == key && !button->value()) {
+               button->take_focus();                                              // move focus to this button
+               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
+               button->do_callback();                                             // invoke the button's callback
+               ret = 1;
+       }
+       else
+               ret = 0;
+
+       if (Fl::event_key() == key)
+               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
+
+       return ret;
+}
diff --git a/src/gui/elems/channel.h b/src/gui/elems/channel.h
new file mode 100644 (file)
index 0000000..33dc00d
--- /dev/null
@@ -0,0 +1,139 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_CHANNEL_H
+#define GE_CHANNEL_H
+
+
+#include <FL/Fl_Group.H>
+
+
+class geChannel : public Fl_Group
+{
+protected:
+
+       /* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of
+       pixels to shrink sampleButton. */
+
+#ifdef WITH_VST
+       static const int BREAK_READ_ACTIONS = 240;
+       static const int BREAK_MODE_BOX     = 216;
+       static const int BREAK_FX           = 192;
+       static const int BREAK_ARM          = 168;
+#else
+       static const int BREAK_READ_ACTIONS = 216;
+       static const int BREAK_MODE_BOX     = 192;
+       static const int BREAK_ARM          = 168;
+#endif
+
+       static void cb_arm           (Fl_Widget *v, void *p);
+       static void cb_mute          (Fl_Widget *v, void *p);
+       static void cb_solo          (Fl_Widget *v, void *p);
+       static void cb_changeVol     (Fl_Widget *v, void *p);
+#ifdef WITH_VST
+               static void cb_openFxWindow(Fl_Widget *v, void *p);
+#endif
+
+       inline void __cb_mute();
+       inline void __cb_arm();
+       inline void __cb_solo();
+       inline void __cb_changeVol();
+#ifdef WITH_VST
+               inline void __cb_openFxWindow();
+#endif
+
+       /* blink
+        * blink button when channel is in wait/ending status. */
+
+       void blink();
+
+       /* setColorByStatus
+        * update colors depending on channel status. */
+
+       void setColorsByStatus(int playStatus, int recStatus);
+
+       /* handleKey
+        * method wrapped by virtual handle(int e). */
+
+       int handleKey(int e, int key);
+
+       /* packWidgets
+       Spread widgets across available space. */
+
+       void packWidgets();
+
+public:
+
+       geChannel(int x, int y, int w, int h, int type, class Channel *ch);
+
+       /* reset
+        * reset channel to initial status. */
+
+       virtual void reset() = 0;
+
+       /* update
+        * update the label of sample button and everything else such as 'R'
+        * button, key box and so on, according to global values. */
+
+       virtual void update() = 0;
+
+       /* refresh
+        * update graphics. */
+
+       virtual void refresh() = 0;
+
+       /* keypress
+        * what to do when the corresponding key is pressed. */
+
+       int keyPress(int event);
+
+       /* getColumnIndex
+        * return the numeric index of the column in which this channel is
+        * located. */
+
+       int getColumnIndex();
+
+       class Channel *ch;
+
+       class gButton         *button;
+       class gStatus         *status;
+       class gClick            *arm;
+       class geChannelButton *mainButton;
+       class gClick            *mute;
+       class gClick            *solo;
+       class gDial           *vol;
+#ifdef WITH_VST
+       class gFxButton       *fx;
+#endif
+
+       int type;
+};
+
+
+#endif
diff --git a/src/gui/elems/channelButton.cpp b/src/gui/elems/channelButton.cpp
new file mode 100644 (file)
index 0000000..69d262d
--- /dev/null
@@ -0,0 +1,137 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channelButton
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/const.h"
+#include "../../utils/fs.h"
+#include "channelButton.h"
+
+
+using std::string;
+
+
+geChannelButton::geChannelButton(int x, int y, int w, int h, const char *l)
+  : gClick(x, y, w, h, l), key("") {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setKey(const string &k)
+{
+  key = k;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setKey(int k)
+{
+  if (k == 0)
+    key = "";
+  else {
+    // FIXME - this crap won't work with unicode/utf-8
+    char c = (char) k;
+    key = c;
+  }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::draw()
+{
+  gClick::draw();
+
+  if (key == "")
+    return;
+
+  /* draw background */
+
+  fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
+
+  /* draw key */
+
+  fl_color(COLOR_TEXT_0);
+  fl_font(FL_HELVETICA, 11);
+  fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setInputRecordMode()
+{
+  bgColor0 = COLOR_BG_3;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setActionRecordMode()
+{
+  bgColor0 = COLOR_BG_4;
+  txtColor = COLOR_TEXT_0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setDefaultMode(const char *l)
+{
+  bgColor0 = COLOR_BG_0;
+       bdColor  = COLOR_BD_0;
+       txtColor = COLOR_TEXT_0;
+  if (l)
+    label(l);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setPlayMode()
+{
+  bgColor0 = COLOR_BG_2;
+  bdColor  = COLOR_BD_1;
+  txtColor = COLOR_TEXT_1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannelButton::setEndingMode()
+{
+  bgColor0 = COLOR_BD_0;
+}
diff --git a/src/gui/elems/channelButton.h b/src/gui/elems/channelButton.h
new file mode 100644 (file)
index 0000000..da08cd8
--- /dev/null
@@ -0,0 +1,63 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_channelButton
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_CHANNEL_BUTTON_H
+#define GE_CHANNEL_BUTTON_H
+
+
+#include "ge_mixed.h"
+
+
+using std::string;
+
+
+class geChannelButton : public gClick
+{
+private:
+
+       string key;
+
+public:
+
+       geChannelButton(int x, int y, int w, int h, const char *l=0);
+
+       virtual int handle(int e) = 0;
+
+       void draw();
+       void setKey(const string &k);
+       void setKey(int k);
+       void setPlayMode();
+       void setEndingMode();
+       void setDefaultMode(const char *l=0);
+       void setInputRecordMode();
+       void setActionRecordMode();
+};
+
+
+#endif
diff --git a/src/gui/elems/envelopeEditor.cpp b/src/gui/elems/envelopeEditor.cpp
new file mode 100644 (file)
index 0000000..7ade209
--- /dev/null
@@ -0,0 +1,405 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_envelopeWidget
+ *
+ * Parent class of any envelope controller, from volume to VST parameter
+ * automations.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/channel.h"
+#include "../../core/recorder.h"
+#include "../../core/mixer.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_keyboard.h"
+#include "envelopeEditor.h"
+
+
+extern Mixer         G_Mixer;
+extern Recorder      G_Recorder;
+extern gdMainWindow *G_MainWin;
+
+
+geEnvelopeEditor::geEnvelopeEditor(int x, int y, gdActionEditor *pParent,
+       int type, int range, const char *l)
+       :       geBaseActionEditor(x, y, 200, 80, pParent),
+               l                 (l),
+               type              (type),
+               range             (range),
+               selectedPoint     (-1),
+               draggedPoint      (-1)
+{
+       size(pParent->totalWidth, h());
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+geEnvelopeEditor::~geEnvelopeEditor() {
+       clearPoints();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geEnvelopeEditor::addPoint(int frame, int iValue, float fValue, int px, int py) {
+       point p;
+       p.frame  = frame;
+       p.iValue = iValue;
+       p.fValue = fValue;
+       p.x = px;
+       p.y = py;
+       points.push_back(p);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geEnvelopeEditor::updateActions() {
+       for (unsigned i=0; i<points.size(); i++)
+               points.at(i).x = points.at(i).frame / pParent->zoom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geEnvelopeEditor::draw() {
+
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT));
+
+       int pxOld = x()-3;
+       int pyOld = y()+1;
+       int pxNew = 0;
+       int pyNew = 0;
+
+       fl_color(COLOR_BG_2);
+
+       for (unsigned i=0; i<points.size(); i++) {
+
+               pxNew = points.at(i).x+x()-3;
+               pyNew = points.at(i).y+y();
+
+               if (selectedPoint == (int) i) {
+                       fl_color(COLOR_BD_1);
+                       fl_rectf(pxNew, pyNew, 7, 7);
+                       fl_color(COLOR_BG_2);
+               }
+               else
+                       fl_rectf(pxNew, pyNew, 7, 7);
+
+               if (i > 0)
+                       fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3);
+
+               pxOld = pxNew;
+               pyOld = pyNew;
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int geEnvelopeEditor::handle(int e) {
+
+       /* Adding an action: no further checks required, just record it on frame
+        * mx*pParent->zoom. Deleting action is trickier: find the active
+        * point and derive from it the corresponding frame. */
+
+       int ret = 0;
+       int mx  = Fl::event_x()-x();  // mouse x
+       int my  = Fl::event_y()-y();  // mouse y
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       ret = 1;
+                       break;
+               }
+
+               case FL_MOVE: {
+                       selectedPoint = getSelectedPoint();
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH: {
+
+                       /* left click on point: drag
+                        * right click on point: delete
+                        * left click on void: add */
+
+                       if (Fl::event_button1()) {
+
+                               if (selectedPoint != -1) {
+                                       draggedPoint = selectedPoint;
+                               }
+                               else {
+
+                                       /* top & border fix */
+
+                                       if (my > h()-8) my = h()-8;
+                                       if (mx > pParent->coverX-x()) mx = pParent->coverX-x();
+
+                                       if (range == RANGE_FLOAT) {
+
+                                               /* if this is the first point ever, add other two points at the beginning
+                                                * and the end of the range */
+
+                                               if (points.size() == 0) {
+                                                       addPoint(0, 0, 1.0f, 0, 1);
+                                                       G_Recorder.rec(pParent->chan->index, type, 0, 0, 1.0f);
+                                                       addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1);
+                                                       G_Recorder.rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f);
+                                               }
+
+                                               /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */
+
+                                               int frame   = mx * pParent->zoom;
+                                               float value = (my - h() + 8) / (float) (1 - h() + 8);
+                                               addPoint(frame, 0, value, mx, my);
+                                               G_Recorder.rec(pParent->chan->index, type, frame, 0, value);
+                                               G_Recorder.sortActions();
+                                               sortPoints();
+                                       }
+                                       else {
+                                               /// TODO
+                                       }
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       redraw();
+                               }
+                       }
+                       else {
+
+                               /* right click on point 0 or point size-1 deletes the entire envelope */
+
+                               if (selectedPoint != -1) {
+                                       if (selectedPoint == 0 || (unsigned) selectedPoint == points.size()-1) {
+                                               G_Recorder.clearAction(pParent->chan->index, type);
+                                               points.clear();
+                                       }
+                                       else {
+                                               G_Recorder.deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false);
+                                               G_Recorder.sortActions();
+                                               points.erase(points.begin() + selectedPoint);
+                                       }
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       redraw();
+                               }
+                       }
+
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+                       if (draggedPoint != -1) {
+
+                               if (points.at(draggedPoint).x == previousXPoint) {
+                                       //gu_log("nothing to do\n");
+                               }
+                               else {
+                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
+
+                                       /* x edge correction */
+
+                                       if (newFrame < 0)
+                                               newFrame = 0;
+                                       else if (newFrame > G_Mixer.totalFrames)
+                                               newFrame = G_Mixer.totalFrames;
+
+                                       /* vertical line check */
+
+                                       int vp = verticalPoint(points.at(draggedPoint));
+                                       if (vp == 1)                     newFrame -= 256;
+                                       else if (vp == -1) newFrame += 256;
+
+                                       /*  delete previous point and record a new one */
+
+                                       G_Recorder.deleteAction(pParent->chan->index,   points.at(draggedPoint).frame, type, false);
+
+                                       if (range == RANGE_FLOAT) {
+                                               float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8);
+                                               G_Recorder.rec(pParent->chan->index, type, newFrame, 0, value);
+                                       }
+                                       else {
+                                               /// TODO
+                                       }
+
+                                       G_Recorder.sortActions();
+                                       points.at(draggedPoint).frame = newFrame;
+                                       draggedPoint  = -1;
+                                       selectedPoint = -1;
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       if (draggedPoint != -1) {
+
+                               /* y constraint */
+
+                               if (my > h()-8)
+                                       points.at(draggedPoint).y = h()-8;
+                               else
+                               if (my < 1)
+                                       points.at(draggedPoint).y = 1;
+                               else
+                                       points.at(draggedPoint).y = my;
+
+                               /* x constraint
+                                * constrain the point between two ends (leftBorder-point, point-point,
+                                * point-rightBorder). First & last points cannot be shifted on x */
+
+                               if (draggedPoint == 0)
+                                       points.at(draggedPoint).x = x()-8;
+                               else
+                               if ((unsigned) draggedPoint == points.size()-1)
+                                       points.at(draggedPoint).x = pParent->coverX;
+                               else {
+                                       int prevPoint = points.at(draggedPoint-1).x;
+                                       int nextPoint = points.at(draggedPoint+1).x;
+                                       if (mx <= prevPoint)
+                                               points.at(draggedPoint).x = prevPoint;
+                                       else
+                                       if (mx >= nextPoint)
+                                               points.at(draggedPoint).x = nextPoint;
+                                       //else
+                                       //      points.at(draggedPoint).x = mx;
+                                       else {
+                                               if (pParent->gridTool->isOn())
+                                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mx)-1;
+                                               else
+                                                       points.at(draggedPoint).x = mx;
+                                       }
+                               }
+                               redraw();
+                       }
+
+                       ret = 1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int geEnvelopeEditor::verticalPoint(const point &p) {
+       for (unsigned i=0; i<points.size(); i++) {
+               if (&p == &points.at(i)) {
+                       if (i == 0 || i == points.size()-1)  // first or last point
+                               return 0;
+                       else {
+                               if (points.at(i-1).x == p.x)    // vertical with point[i-1]
+                                       return -1;
+                               else
+                               if (points.at(i+1).x == p.x)    // vertical with point[i+1]
+                                       return 1;
+                       }
+                       break;
+               }
+       }
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geEnvelopeEditor::sortPoints() {
+       for (unsigned i=0; i<points.size(); i++)
+               for (unsigned j=0; j<points.size(); j++)
+                       if (points.at(j).x > points.at(i).x)
+                               std::swap(points.at(j), points.at(i));
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int geEnvelopeEditor::getSelectedPoint() {
+
+       /* point is a 7x7 dot */
+
+       for (unsigned i=0; i<points.size(); i++) {
+               if (Fl::event_x() >= points.at(i).x+x()-4  &&
+                               Fl::event_x() <= points.at(i).x+x()+4  &&
+                               Fl::event_y() >= points.at(i).y+y()    &&
+                               Fl::event_y() <= points.at(i).y+y()+7)
+               return i;
+       }
+       return -1;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geEnvelopeEditor::fill() {
+       points.clear();
+       for (unsigned i=0; i<G_Recorder.global.size(); i++)
+               for (unsigned j=0; j<G_Recorder.global.at(i).size(); j++) {
+                       Recorder::action *a = G_Recorder.global.at(i).at(j);
+                       if (a->type == type && a->chan == pParent->chan->index) {
+                               if (range == RANGE_FLOAT)
+                                       addPoint(
+                                               a->frame,                      // frame
+                                               0,                             // int value (unused)
+                                               a->fValue,                     // float value
+                                               a->frame / pParent->zoom,       // x
+                                               ((1-h()+8)*a->fValue)+h()-8);  // y = (b-a)x + a (line between two points)
+                               // else: TODO
+                       }
+               }
+
+}
diff --git a/src/gui/elems/envelopeEditor.h b/src/gui/elems/envelopeEditor.h
new file mode 100644 (file)
index 0000000..f7dade4
--- /dev/null
@@ -0,0 +1,122 @@
+/* ---------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_envelopeWidget
+ *
+ * parent class of any envelope controller, from volume to VST parameter
+ * automations.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ------------------------------------------------------------------ */
+
+#ifndef __GE_ENVELOPECHANNEL_H__
+#define __GE_ENVELOPECHANNEL_H__
+
+
+#include <vector>
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "../../utils/fs.h"
+#include "baseActionEditor.h"
+
+
+using std::vector;
+
+
+class geEnvelopeEditor : public geBaseActionEditor
+{
+       const char *l;      // internal label
+       int         type;   // type of action
+       int         range;
+
+       /* point
+        * a single dot in the graph. x = relative frame, y = relative value */
+
+       struct point
+       {
+               int   frame;
+               int   iValue;
+               float fValue;
+               int   x;
+               int   y;
+       };
+
+       /* points
+        * array of points, filled by fillPoints() */
+
+       vector<point> points;
+
+       /* selectedPoint
+        * which point we are selecting? */
+
+       int selectedPoint;
+
+       /* draggedPoint
+        * which point we are dragging? */
+
+       int draggedPoint;
+
+       /* previousXPoint
+        * x coordinate of point at time t-1. Used to check effective shifts */
+
+       int previousXPoint;
+
+       void draw();
+
+       int handle(int e);
+
+       int getSelectedPoint();
+
+       void sortPoints();
+
+       /* verticalPoint
+        * check if two points form a vertical line. In that case the frame value
+        * would be the same and recorder would go crazy, so shift by a small value
+        * of frames to create a minimal fadein/fadeout level. Return 0: no
+        * vertical points; return 1: vertical with the next one, return -1: vertical
+        * with the previous one. */
+
+       int verticalPoint(const point &p);
+
+public:
+
+       geEnvelopeEditor(int x, int y, gdActionEditor *pParent, int type, int range, const char *l);
+       ~geEnvelopeEditor();
+
+       /* addPoint
+        * add a point made of frame+value to internal points[]. */
+
+       void addPoint(int frame, int iValue=0, float fValue=0.0f, int x=-1, int y=-1);
+
+       void updateActions();
+
+       /* fill
+        * parse recorder's stack and fill the widget with points. It's up to
+        * the caller to call this method as initialization. */
+
+       void fill();
+
+       inline void clearPoints() { points.clear(); }
+};
+
+#endif
diff --git a/src/gui/elems/ge_actionChannel.cpp b/src/gui/elems/ge_actionChannel.cpp
deleted file mode 100644 (file)
index 81b453a..0000000
+++ /dev/null
@@ -1,678 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "../../core/conf.h"
-#include "../../core/channel.h"
-#include "../../core/sampleChannel.h"
-#include "../../glue/glue.h"
-#include "../../utils/log.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "ge_keyboard.h"
-#include "ge_actionChannel.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-extern Conf             G_Conf;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch)
-  : gActionWidget(x, y, 200, 40, pParent),
-    ch           (ch),
-    selected     (NULL)
-{
-       size(pParent->totalWidth, h());
-
-       /* add actions when the window opens. Their position is zoom-based;
-        * each frame is / 2 because we don't care about stereo infos. */
-
-       for (unsigned i=0; i<recorder::frames.size(); i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-
-                       recorder::action *action = recorder::global.at(i).at(j);
-
-      /* Don't show actions:
-      - that don't belong to the displayed channel (!= pParent->chan->index);
-      - that are covered by the grey area (> G_Mixer.totalFrames);
-      - of type ACTION_KILLCHAN in a SINGLE_PRESS channel. They cannot be
-        recorded in such mode, but they can exist if you change from another
-        mode to singlepress;
-      - of type ACTION_KEYREL in a SINGLE_PRESS channel. It's up to gAction to
-        find the other piece (namely frame_b)
-      - not of types ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN */
-
-      if ((action->chan != pParent->chan->index)                            ||
-          (recorder::frames.at(i) > G_Mixer.totalFrames)                    ||
-          (action->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS)     ||
-          (action->type == ACTION_KEYREL && ch->mode == SINGLE_PRESS)       ||
-          (action->type & ~(ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN))
-      )
-        continue;
-
-                       int ax = x + (action->frame / pParent->zoom);
-                       gAction *a = new gAction(
-                                       ax,               // x
-                                       y + 4,            // y
-                                       h() - 8,          // h
-                                       action->frame,    // frame_a
-                                       i,                // n. of recordings
-                                       pParent,          // pointer to the pParent window
-                                       ch,               // pointer to SampleChannel
-                                       false,            // record = false: don't record it, we are just displaying it!
-                                       action->type);    // type of action
-                       add(a);
-               }
-       }
-       end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gAction *gActionChannel::getSelectedAction()
-{
-       for (int i=0; i<children(); i++) {
-               int action_x  = ((gAction*)child(i))->x();
-               int action_w  = ((gAction*)child(i))->w();
-               if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w)
-                       return (gAction*)child(i);
-       }
-       return NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gActionChannel::updateActions()
-{
-       /* when zooming, don't delete and re-add actions, just MOVE them. This
-        * function shifts the action by a zoom factor. Those singlepress are
-        * stretched, as well */
-
-       gAction *a;
-       for (int i=0; i<children(); i++) {
-
-               a = (gAction*)child(i);
-               int newX = x() + (a->frame_a / pParent->zoom);
-
-               if (ch->mode == SINGLE_PRESS) {
-                       int newW = ((a->frame_b - a->frame_a) / pParent->zoom);
-                       if (newW < gAction::MIN_WIDTH)
-                               newW = gAction::MIN_WIDTH;
-                       a->resize(newX, a->y(), newW, a->h());
-               }
-               else
-                       a->resize(newX, a->y(), gAction::MIN_WIDTH, a->h());
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gActionChannel::draw()
-{
-       /* draw basic boundaries (+ beat bars) and hide the unused area. Then
-        * draw the children (the actions) */
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       if (active())
-               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
-       else
-               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));  /// FIXME h() is too much!
-
-       draw_children();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gActionChannel::handle(int e)
-{
-       int ret = Fl_Group::handle(e);
-
-       /* do nothing if the widget is deactivated. It could happen for loopmode
-        * channels */
-
-       if (!active())
-               return 1;
-
-       switch (e) {
-
-               case FL_DRAG: {
-
-      if (selected == NULL) {  // if you drag an empty area
-        ret = 1;
-        break;
-      }
-
-                       /* if onLeftEdge o onRightEdge are true it means that you're resizing
-                        * an action. Otherwise move the widget. */
-
-                       if (selected->onLeftEdge || selected->onRightEdge) {
-
-                               /* some checks: a) cannot resize an action < N pixels, b) no beyond zero,
-                                * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */
-
-                               if (selected->onRightEdge) {
-
-                                       int aw = Fl::event_x()-selected->x();
-                                       int ah = selected->h();
-
-                                       if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH)
-                                               aw = gAction::MIN_WIDTH;
-                                       else
-                                       if (Fl::event_x() > pParent->coverX)
-                                               aw = pParent->coverX-selected->x();
-
-                                       selected->size(aw, ah);
-                               }
-                               else {
-
-                                       int ax = Fl::event_x();
-                                       int ay = selected->y();
-                                       int aw = selected->x()-Fl::event_x()+selected->w();
-                                       int ah = selected->h();
-
-                                       if (Fl::event_x() < x()) {
-                                               ax = x();
-                                               aw = selected->w()+selected->x()-x();
-                                       }
-                                       else
-                                       if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) {
-                                               ax = selected->x()+selected->w()-gAction::MIN_WIDTH;
-                                               aw = gAction::MIN_WIDTH;
-                                       }
-                                       selected->resize(ax, ay, aw, ah);
-                               }
-                       }
-
-      /* move the widget around */
-
-                       else {
-                               int real_x = Fl::event_x() - actionPickPoint;
-                               if (real_x < x())                                  // don't go beyond the left border
-                                       selected->position(x(), selected->y());
-                               else
-                               if (real_x+selected->w() > pParent->coverX+x())         // don't go beyond the right border
-                                       selected->position(pParent->coverX+x()-selected->w(), selected->y());
-                               else {
-                                       if (pParent->gridTool->isOn()) {
-                                               int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1;
-                                               selected->position(snpx, selected->y());
-                                       }
-                                       else
-                                               selected->position(real_x, selected->y());
-                               }
-                       }
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH:   {
-
-                       if (Fl::event_button1()) {
-
-                               /* avoid at all costs two overlapping actions. We use 'selected' because
-                                * the selected action can be reused in FL_DRAG, in case you want to move
-                                * it. */
-
-                               selected = getSelectedAction();
-
-                               if (selected == NULL) {
-
-                                       /* avoid click on grey area */
-
-                                       if (Fl::event_x() >= pParent->coverX) {
-                                               ret = 1;
-                                               break;
-                                       }
-
-                                       /* snap function, if enabled */
-
-                                       int ax = Fl::event_x();
-                                       int fx = (ax - x()) * pParent->zoom;
-                                       if (pParent->gridTool->isOn()) {
-                                               ax = pParent->gridTool->getSnapPoint(ax-x()) + x() -1;
-                                               fx = pParent->gridTool->getSnapFrame(ax-x());
-
-                                               /* with snap=on an action can fall onto another */
-
-                                               if (actionCollides(fx)) {
-                                                       ret = 1;
-                                                       break;
-                                               }
-                                       }
-
-                                       gAction *a = new gAction(
-                                                       ax,                                   // x
-                                                       y()+4,                                // y
-                                                       h()-8,                                // h
-                                                       fx,                                                                                                                                             // frame_a
-                                                       recorder::frames.size()-1,            // n. of actions recorded
-                                                       pParent,                              // pParent window pointer
-                                                       ch,                                   // pointer to SampleChannel
-                                                       true,                                 // record = true: record it!
-                                                       pParent->getActionType());            // type of action
-                                       add(a);
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); // mainWindow update
-                                       redraw();
-                                       ret = 1;
-                               }
-                               else {
-                                       actionOriginalX = selected->x();
-                                       actionOriginalW = selected->w();
-                                       actionPickPoint = Fl::event_x() - selected->x();
-                                       ret = 1;   // for dragging
-                               }
-                       }
-                       else
-                       if (Fl::event_button3()) {
-                               gAction *a = getSelectedAction();
-                               if (a != NULL) {
-                                       a->delAction();
-                                       remove(a);
-                                       delete a;
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel);
-                                       redraw();
-                                       ret = 1;
-                               }
-                       }
-                       break;
-               }
-               case FL_RELEASE: {
-
-                       if (selected == NULL) {
-                               ret = 1;
-                               break;
-                       }
-
-                       /* noChanges = true when you click on an action without doing anything
-                        * (dragging or moving it). */
-
-                       bool noChanges = false;
-                       if (actionOriginalX == selected->x())
-                               noChanges = true;
-                       if (ch->mode == SINGLE_PRESS &&
-                                       actionOriginalX+actionOriginalW != selected->x()+selected->w())
-                               noChanges = false;
-
-                       if (noChanges) {
-                               ret = 1;
-                               selected = NULL;
-                               break;
-                       }
-
-                       /* step 1: check if the action doesn't overlap with another one.
-                        * In case of overlap the moved action returns to the original X
-                        * value ("actionOriginalX"). */
-
-                       bool overlap = false;
-                       for (int i=0; i<children() && !overlap; i++) {
-
-                               /* never check against itself. */
-
-                               if ((gAction*)child(i) == selected)
-                                       continue;
-
-                               int action_x  = ((gAction*)child(i))->x();
-                               int action_w  = ((gAction*)child(i))->w();
-                               if (ch->mode == SINGLE_PRESS) {
-
-                                       /* when 2 segments overlap?
-                                        * start = the highest value between the two starting points
-                                        * end   = the lowest value between the two ending points
-                                        * if start < end then there's an overlap of end-start pixels. */
-
-                                        int start = action_x >= selected->x() ? action_x : selected->x();
-                                        int end   = action_x+action_w < selected->x()+selected->w() ? action_x+action_w : selected->x()+selected->w();
-                                        if (start < end) {
-                                               selected->resize(actionOriginalX, selected->y(), actionOriginalW, selected->h());
-                                               redraw();
-                                               overlap = true;   // one overlap: stop checking
-                                       }
-                               }
-                               else {
-                                       if (selected->x() == action_x) {
-                                               selected->position(actionOriginalX, selected->y());
-                                               redraw();
-                                               overlap = true;   // one overlap: stop checking
-                                       }
-                               }
-                       }
-
-                       /* step 2: no overlap? then update the coordinates of the action, ie
-                        * delete the previous rec and create a new one.
-                        * Anyway the selected action becomes NULL, because when you release
-                        * the mouse button the dragging process ends. */
-
-                       if (!overlap) {
-                               if (pParent->gridTool->isOn()) {
-                                       int f = pParent->gridTool->getSnapFrame(selected->absx());
-                                       selected->moveAction(f);
-                               }
-                               else
-                                       selected->moveAction();
-                       }
-                       selected = NULL;
-                       ret = 1;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gActionChannel::actionCollides(int frame)
-{
-       /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't
-        * overlap the head (frame) of the new one. First the general case, yet. */
-
-       bool collision = false;
-
-       for (int i=0; i<children() && !collision; i++)
-               if (((gAction*) child(i))->frame_a == frame)
-                       collision = true;
-
-       if (ch->mode == SINGLE_PRESS) {
-               for (int i=0; i<children() && !collision; i++) {
-                       gAction *c = ((gAction*) child(i));
-                       if (frame <= c->frame_b && frame >= c->frame_a)
-                               collision = true;
-               }
-       }
-
-       return collision;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-/** TODO - index is useless?
- *  TODO - pass a record::action pointer and let gAction compute values */
-
-gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEditor *parent, SampleChannel *ch, bool record, char type)
-: Fl_Box     (X, Y, MIN_WIDTH, H),
-  selected   (false),
-  index      (index),
-  parent     (parent),
-  ch         (ch),
-  type       (type),
-  frame_a    (frame_a),
-  onRightEdge(false),
-  onLeftEdge (false)
-{
-       /* bool 'record' defines how to understand the action.
-        * record = false: don't record it, just show it. It happens when you
-        * open the editor with some actions to be shown.
-        *
-        * record = true: record it AND show it. It happens when you click on
-        * an empty area in order to add a new actions. First you record it
-        * (addAction()) then you show it (FLTK::Draw()) */
-
-       if (record)
-               addAction();
-
-       /* in order to show a singlepress action we must compute the frame_b. We
-        * do that after the possible recording, otherwise we don't know which
-        * key_release is associated. */
-
-       if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) {
-               recorder::action *a2 = NULL;
-               recorder::getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2);
-               if (a2) {
-                       frame_b = a2->frame;
-                       w((frame_b - frame_a)/parent->zoom);
-               }
-               else
-                       gLog("[gActionChannel] frame_b not found! [%d:???]\n", frame_a);
-
-       /* a singlepress action narrower than 8 pixel is useless. So check it.
-        * Warning: if an action is 8 px narrow, it has no body space to drag
-        * it. It's up to the user to zoom in and drag it. */
-
-               if (w() < MIN_WIDTH)
-                       size(MIN_WIDTH, h());
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gAction::draw()
-{
-       int color;
-       if (selected)  /// && gActionChannel !disabled
-               color = COLOR_BD_1;
-       else
-               color = COLOR_BG_2;
-
-       if (ch->mode == SINGLE_PRESS) {
-               fl_rectf(x(), y(), w(), h(), (Fl_Color) color);
-       }
-       else {
-               if (type == ACTION_KILLCHAN)
-                       fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-               else {
-                       fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-                       if (type == ACTION_KEYPRESS)
-                               fl_rectf(x()+3, y()+h()-11, 2, 8, COLOR_BD_0);
-                       else
-                       if  (type == ACTION_KEYREL)
-                               fl_rectf(x()+3, y()+3, 2, 8, COLOR_BD_0);
-               }
-       }
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gAction::handle(int e)
-{
-       /* ret = 0 sends the event to the parent window. */
-
-       int ret = 0;
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       selected = true;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-               case FL_LEAVE: {
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       selected = false;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-               case FL_MOVE: {
-
-                       /* handling of the two margins, left & right. 4 pixels are good enough */
-
-                       if (ch->mode == SINGLE_PRESS) {
-                               onLeftEdge  = false;
-                               onRightEdge = false;
-                               if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
-                                       onLeftEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                               if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
-                                       onRightEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       }
-               }
-       }
-
-       return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gAction::addAction()
-{
-       /* always check frame parity */
-
-       if (frame_a % 2 != 0)
-               frame_a++;
-
-       /* anatomy of an action
-        * ____[#######]_____ (a) is the left margin, ACTION_KEYPRESS. (b) is
-        *     a       b      the right margin, the ACTION_KEYREL. This is the
-        * theory behind the singleshot.press actions; for any other kind the
-        * (b) is just a graphical and meaningless point. */
-
-       if (ch->mode == SINGLE_PRESS) {
-               recorder::rec(parent->chan->index, ACTION_KEYPRESS, frame_a);
-               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_a+4096);
-               //gLog("action added, [%d, %d]\n", frame_a, frame_a+4096);
-       }
-       else {
-               recorder::rec(parent->chan->index, parent->getActionType(), frame_a);
-               //gLog("action added, [%d]\n", frame_a);
-       }
-
-       recorder::sortActions();
-
-       index++; // important!
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gAction::delAction()
-{
-       /* if SINGLE_PRESS you must delete both the keypress and the keyrelease
-        * actions. */
-
-       if (ch->mode == SINGLE_PRESS) {
-               recorder::deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false);
-               recorder::deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false);
-       }
-       else
-               recorder::deleteAction(parent->chan->index, frame_a, type, false);
-
-       /* restore the initial cursor shape, in case you delete an action and
-        * the double arrow (for resizing) is displayed */
-
-       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gAction::moveAction(int frame_a)
-{
-       /* easy one: delete previous action and record the new ones. As usual,
-        * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame
-        * value. */
-
-       delAction();
-
-       if (frame_a != -1)
-               this->frame_a = frame_a;
-       else
-               this->frame_a = xToFrame_a();
-
-
-       /* always check frame parity */
-
-       if (this->frame_a % 2 != 0)
-               this->frame_a++;
-
-       recorder::rec(parent->chan->index, type, this->frame_a);
-
-       if (ch->mode == SINGLE_PRESS) {
-               frame_b = xToFrame_b();
-               recorder::rec(parent->chan->index, ACTION_KEYREL, frame_b);
-       }
-
-       recorder::sortActions();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gAction::absx()
-{
-       return x() - parent->ac->x();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gAction::xToFrame_a()
-{
-       return (absx()) * parent->zoom;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gAction::xToFrame_b()
-{
-       return (absx() + w()) * parent->zoom;
-}
diff --git a/src/gui/elems/ge_actionChannel.h b/src/gui/elems/ge_actionChannel.h
deleted file mode 100644 (file)
index 051feea..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_ACTIONCHANNEL_H
-#define GE_ACTIONCHANNEL_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Box.H>
-#include "../../utils/gui_utils.h"
-#include "../../core/mixer.h"
-#include "../../core/recorder.h"
-#include "ge_actionWidget.h"
-
-
-class gAction : public Fl_Box
-{
-private:
-
-       bool                  selected;
-       unsigned              index;
-  class gdActionEditor *parent;   // pointer to parent (gActionEditor)
-       class SampleChannel  *ch;
-  char                  type;     // type of action
-
-public:
-
-       gAction(int x, int y, int h, int frame_a, unsigned index,
-                                 gdActionEditor *parent, class SampleChannel *ch, bool record,
-                           char type);
-       void draw();
-       int  handle(int e);
-       void addAction();
-       void delAction();
-
-       /* moveAction
-        * shift the action on the x-axis and update Recorder. If frame_a != -1
-        * use the new frame in input (used while snapping) */
-
-       void moveAction(int frame_a=-1);
-
-       /* absx
-        * x() is relative to scrolling position. absx() returns the absolute
-        * x value of the action, from the leftmost edge. */
-
-       int  absx();
-
-       /* xToFrame_a,b
-        * return the real frames of x() position */
-
-       int xToFrame_a();
-       int xToFrame_b();
-
-       int frame_a;  // initial frame (KEYPRESS for singlemode.press)
-       int frame_b;  // terminal frame (KEYREL for singlemode.press, null for others)
-
-       bool onRightEdge;
-       bool onLeftEdge;
-
-       static const int MIN_WIDTH = 8;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gActionChannel : public gActionWidget
-{
-
-private:
-
-       class SampleChannel *ch;
-
-       /* getSelectedAction
-        * get the action under the mouse. NULL if nothing found. */
-
-       gAction *getSelectedAction();
-
-       /* selected
-        * pointer to the selected action. Useful when dragging around. */
-
-       gAction *selected;
-
-       /* actionOriginalX, actionOriginalW
-        * x and w of the action, when moved. Useful for checking if the action
-        * overlaps another one: in that case the moved action returns to
-        * actionOriginalX (and to actionOriginalW if resized). */
-
-       int actionOriginalX;
-       int actionOriginalW;
-
-       /* actionPickPoint
-        * the precise x point in which the action has been picked with the mouse,
-        * before a dragging action. */
-
-       int actionPickPoint;
-
-
-       /* actionCollides
-        * true if an action collides with another. Used while adding new points
-        * with snap active.*/
-
-       bool actionCollides(int frame);
-
-public:
-
-       gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch);
-       void draw();
-       int  handle(int e);
-       void updateActions();
-};
-
-
-#endif
diff --git a/src/gui/elems/ge_actionWidget.cpp b/src/gui/elems/ge_actionWidget.cpp
deleted file mode 100644 (file)
index 562a591..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionWidget
- *
- * pParent class of any widget inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "../../core/mixer.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "ge_actionWidget.h"
-#include "ge_mixed.h"
-
-
-extern Mixer G_Mixer;
-
-
-gActionWidget::gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent)
-       :       Fl_Group(x, y, w, h), pParent(pParent) {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gActionWidget::~gActionWidget() {}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gActionWidget::baseDraw(bool clear) {
-
-       /* clear the screen */
-
-       if (clear)
-               fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
-
-       /* draw the container */
-
-       fl_color(COLOR_BD_0);
-       fl_rect(x(), y(), w(), h());
-
-       /* grid drawing, if > 1 */
-
-       if (pParent->gridTool->getValue() > 1) {
-
-               fl_color(fl_rgb_color(54, 54, 54));
-               fl_line_style(FL_DASH, 0, NULL);
-
-               for (int i=0; i<(int) pParent->gridTool->points.size(); i++) {
-                       int px = pParent->gridTool->points.at(i)+x()-1;
-                       fl_line(px, y()+1, px, y()+h()-2);
-               }
-               fl_line_style(0);
-       }
-
-       /* bars and beats drawing */
-
-       fl_color(COLOR_BD_0);
-       for (int i=0; i<(int) pParent->gridTool->beats.size(); i++) {
-               int px = pParent->gridTool->beats.at(i)+x()-1;
-               fl_line(px, y()+1, px, y()+h()-2);
-       }
-
-       fl_color(COLOR_BG_2);
-       for (int i=0; i<(int) pParent->gridTool->bars.size(); i++) {
-               int px = pParent->gridTool->bars.at(i)+x()-1;
-               fl_line(px, y()+1, px, y()+h()-2);
-       }
-
-       /* cover unused area. Avoid drawing cover if width == 0 (i.e. beats
-        * are 32) */
-
-       int coverWidth = pParent->totalWidth-pParent->coverX;
-       if (coverWidth != 0)
-               fl_rectf(pParent->coverX+x(), y()+1, coverWidth, h()-2, COLOR_BG_1);
-}
diff --git a/src/gui/elems/ge_actionWidget.h b/src/gui/elems/ge_actionWidget.h
deleted file mode 100644 (file)
index 1536b29..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_actionWidget
- *
- * parent class of any widget inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __GE_ACTIONWIDGET_H__
-#define __GE_ACTIONWIDGET_H__
-
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "../../core/const.h"
-
-
-class gActionWidget : public Fl_Group {
-
-protected:
-       class gdActionEditor *pParent;
-       void  baseDraw(bool clear=true);
-
-public:
-       virtual void updateActions() = 0;
-
-       gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent);
-       ~gActionWidget();
-};
-
-#endif
index be64cc85f8c29ac77bc83bc57beb95a3488791e8..9ae32351f4f9f0e4f4d01416d091b4fd86100270 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <limits.h>
 #include "../../core/const.h"
-#include "../../utils/utils.h"
+#include "../../utils/fs.h"
 #include "../../utils/string.h"
 #include "../../utils/log.h"
 #include "../dialogs/gd_browser.h"
@@ -122,7 +122,7 @@ int gBrowser::handle(int e)
 
 string gBrowser::getCurrentDir()
 {
-  return normalize(gGetRealPath(currentDir));
+  return normalize(gu_getRealPath(currentDir));
 }
 
 
@@ -137,7 +137,7 @@ string gBrowser::getSelectedItem(bool fullPath)
   if (value() == 0)  // no rows selected? return current directory
     return normalize(currentDir);
   else
-    return normalize(gGetRealPath(currentDir + G_SLASH + normalize(text(value()))));
+    return normalize(gu_getRealPath(currentDir + G_SLASH + normalize(text(value()))));
 }
 
 
@@ -158,12 +158,14 @@ string gBrowser::normalize(const string &s)
 {
   string out = s;
 
-  /* our crappy version of Clang doesn't seem to support std::string::back() */
+  /* If string ends with G_SLASH, remove it. Don't do it if has length > 1, it 
+  means that the string is just '/'. Note: our crappy version of Clang doesn't 
+  seem to support std::string::back() */
 
 #ifdef __APPLE__
-  if (out[out.length() - 1] == G_SLASH)
+  if (out[out.length() - 1] == G_SLASH && out.length() > 1)
 #else
-  if (out.back() == G_SLASH)
+  if (out.back() == G_SLASH && out.length() > 1)
 #endif
 
     out = out.substr(0, out.size()-1);
diff --git a/src/gui/elems/ge_channel.cpp b/src/gui/elems/ge_channel.cpp
deleted file mode 100644 (file)
index 63dd719..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../../core/mixer.h"
-#include "../../core/conf.h"
-#include "../../core/patch_DEPR_.h"
-#include "../../core/graphics.h"
-#include "../../core/channel.h"
-#include "../../core/wave.h"
-#include "../../core/sampleChannel.h"
-#include "../../core/midiChannel.h"
-#include "../../glue/glue.h"
-#include "../../utils/gui_utils.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "../dialogs/gd_keyGrabber.h"
-#include "../dialogs/gd_midiInput.h"
-#include "../dialogs/gd_editor.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "../dialogs/gd_warnings.h"
-#include "../dialogs/gd_browser.h"
-#include "../dialogs/gd_midiOutput.h"
-#include "ge_keyboard.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch_DEPR_   G_Patch_DEPR_;
-extern gdMainWindow *mainWin;
-
-
-gChannel::gChannel(int X, int Y, int W, int H, int type)
- : Fl_Group(X, Y, W, H, NULL), type(type) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gChannel::getColumnIndex()
-{
-       return ((gColumn*)parent())->getIndex();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannel::blink()
-{
-       if (gu_getBlinker() > 6)
-               mainButton->setPlayMode();
-       else
-    mainButton->setDefaultMode();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannel::setColorsByStatus(int playStatus, int recStatus)
-{
-  switch (playStatus) {
-    case STATUS_OFF:
-               mainButton->setDefaultMode();
-      button->imgOn  = channelPlay_xpm;
-      button->imgOff = channelStop_xpm;
-      button->redraw();
-      break;
-    case STATUS_PLAY:
-      mainButton->setPlayMode();
-      button->imgOn  = channelStop_xpm;
-      button->imgOff = channelPlay_xpm;
-      button->redraw();
-      break;
-    case STATUS_WAIT:
-      blink();
-      break;
-    case STATUS_ENDING:
-      mainButton->setEndingMode();
-      break;
-  }
-
-  switch (recStatus) {
-    case REC_WAITING:
-      blink();
-      break;
-    case REC_ENDING:
-      mainButton->setEndingMode();
-      break;
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gChannel::handleKey(int e, int key)
-{
-       int ret;
-       if (e == FL_KEYDOWN && button->value())                              // key already pressed! skip it
-               ret = 1;
-       else
-       if (Fl::event_key() == key && !button->value()) {
-               button->take_focus();                                              // move focus to this button
-               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
-               button->do_callback();                                             // invoke the button's callback
-               ret = 1;
-       }
-       else
-               ret = 0;
-
-       if (Fl::event_key() == key)
-               button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0);      // change the button's state
-
-       return ret;
-}
diff --git a/src/gui/elems/ge_channel.h b/src/gui/elems/ge_channel.h
deleted file mode 100644 (file)
index e0c99ac..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_CHANNEL_H
-#define GE_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_mixed.h"
-
-
-class gChannel : public Fl_Group
-{
-protected:
-
-       /* define some breakpoints for dynamic resize */
-
-#ifdef WITH_VST
-       static const int BREAK_READ_ACTIONS = 212;
-       static const int BREAK_MODE_BOX     = 188;
-       static const int BREAK_FX           = 164;
-       static const int BREAK_DELTA        = 120;
-#else
-       static const int BREAK_READ_ACTIONS = 188;
-       static const int BREAK_MODE_BOX     = 164;
-       static const int BREAK_FX           = 140;
-       static const int BREAK_DELTA        = 96;
-#endif
-       static const int BREAK_UNIT         = 24;
-
-       /* blink
-        * blink button when channel is in wait/ending status. */
-
-       void blink();
-
-       /* setColorByStatus
-        * update colors depending on channel status. */
-
-       void setColorsByStatus(int playStatus, int recStatus);
-
-       /* handleKey
-        * method wrapped by virtual handle(int e). */
-
-       int handleKey(int e, int key);
-
-public:
-
-       gChannel(int x, int y, int w, int h, int type);
-
-       /* reset
-        * reset channel to initial status. */
-
-       virtual void reset() = 0;
-
-       /* update
-        * update the label of sample button and everything else such as 'R'
-        * button, key box and so on, according to global values. */
-
-       virtual void update() = 0;
-
-       /* refresh
-        * update graphics. */
-
-       virtual void refresh() = 0;
-
-       /* keypress
-        * what to do when the corresponding key is pressed. */
-
-       virtual int keyPress(int event) = 0;
-
-       /* getColumnIndex
-        * return the numeric index of the column in which this channel is
-        * located. */
-
-       int getColumnIndex();
-
-       class gButton        *button;
-       class gStatus        *status;
-       class gChannelButton *mainButton;
-       class gDial          *vol;
-       class gClick           *mute;
-       class gClick           *solo;
-#ifdef WITH_VST
-       class gFxButton      *fx;
-#endif
-
-       int type;
-};
-
-
-#endif
diff --git a/src/gui/elems/ge_channelButton.cpp b/src/gui/elems/ge_channelButton.cpp
deleted file mode 100644 (file)
index ab6e306..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channelButton
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../../core/const.h"
-#include "../../utils/utils.h"
-#include "ge_channelButton.h"
-
-
-using std::string;
-
-
-gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l)
-  : gClick(x, y, w, h, l), key("") {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setKey(const string &k)
-{
-  key = k;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setKey(int k)
-{
-  if (k == 0)
-    key = "";
-  else {
-    // FIXME - this crap won't work with unicode/utf-8
-    char c = (char) k;
-    key = c;
-  }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::draw()
-{
-  gClick::draw();
-
-  if (key == "")
-    return;
-
-  /* draw background */
-
-  fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
-
-  /* draw key */
-
-  fl_color(COLOR_TEXT_0);
-  fl_font(FL_HELVETICA, 11);
-  fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setInputRecordMode()
-{
-  bgColor0 = COLOR_BG_3;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setActionRecordMode()
-{
-  bgColor0 = COLOR_BG_4;
-  txtColor = COLOR_TEXT_0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setDefaultMode(const char *l)
-{
-  bgColor0 = COLOR_BG_0;
-       bdColor  = COLOR_BD_0;
-       txtColor = COLOR_TEXT_0;
-  if (l)
-    label(l);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setPlayMode()
-{
-  bgColor0 = COLOR_BG_2;
-  bdColor  = COLOR_BD_1;
-  txtColor = COLOR_TEXT_1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gChannelButton::setEndingMode()
-{
-  bgColor0 = COLOR_BD_0;
-}
diff --git a/src/gui/elems/ge_channelButton.h b/src/gui/elems/ge_channelButton.h
deleted file mode 100644 (file)
index 9a1718d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_channelButton
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_CHANNEL_BUTTON_H
-#define GE_CHANNEL_BUTTON_H
-
-
-#include "ge_mixed.h"
-
-
-using std::string;
-
-
-class gChannelButton : public gClick
-{
-private:
-
-       string key;
-
-public:
-
-       gChannelButton(int x, int y, int w, int h, const char *l=0);
-
-       virtual int handle(int e) = 0;
-
-       void draw();
-       void setKey(const string &k);
-       void setKey(int k);
-       void setPlayMode();
-       void setEndingMode();
-       void setDefaultMode(const char *l=0);
-       void setInputRecordMode();
-       void setActionRecordMode();
-};
-
-
-#endif
index 5f0dc4c8b625d107a749a867e88c7aecc93ff4b8..7f8a046e9dbeedd9a9c16fffed28c1a0d8f080a8 100644 (file)
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
 #include "../../core/midiChannel.h"
-#include "../../glue/glue.h"
+#include "../../glue/main.h"
 #include "../../glue/channel.h"
 #include "../../utils/log.h"
+#include "../../utils/string.h"
 #include "../dialogs/gd_mainWindow.h"
 #include "../dialogs/gd_warnings.h"
 #include "../elems/ge_keyboard.h"
 #include "ge_column.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "ge_midiChannel.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "midiChannel.h"
 
 
 extern Mixer                G_Mixer;
@@ -107,13 +108,13 @@ int gColumn::handle(int e)
                }
                case FL_PASTE: {              // handle actual drop (paste) operation
                        vector<std::string> paths;
-                       gSplit(Fl::event_text(), "\n", &paths);
+                       gu_split(Fl::event_text(), "\n", &paths);
                        bool fails = false;
                        int result = 0;
                        for (unsigned i=0; i<paths.size(); i++) {
-                               gLog("[gColumn::handle] loading %s...\n", paths.at(i).c_str());
+                               gu_log("[gColumn::handle] loading %s...\n", paths.at(i).c_str());
                                SampleChannel *c = (SampleChannel*) glue_addChannel(index, CHANNEL_SAMPLE);
-                               result = glue_loadChannel(c, gStripFileUrl(paths.at(i).c_str()).c_str());
+                               result = glue_loadChannel(c, gu_stripFileUrl(paths.at(i)).c_str());
                                if (result != SAMPLE_LOADED_OK) {
                                        deleteChannel(c->guiChannel);
                                        fails = true;
@@ -165,7 +166,7 @@ void gColumn::resize(int X, int Y, int W, int H)
 void gColumn::refreshChannels()
 {
        for (int i=1; i<children(); i++)
-               ((gChannel*) child(i))->refresh();
+               ((geChannel*) child(i))->refresh();
 }
 
 
@@ -196,14 +197,14 @@ void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChan
 /* -------------------------------------------------------------------------- */
 
 
-gChannel *gColumn::addChannel(class Channel *ch)
+geChannel *gColumn::addChannel(Channel *ch)
 {
        int currentY = y() + children() * 24;
-       gChannel *gch = NULL;
+       geChannel *gch = NULL;
        if (ch->type == CHANNEL_SAMPLE)
-               gch = (gSampleChannel*) new gSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch);
+               gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch);
        else
-               gch = (gMidiChannel*) new gMidiChannel(x(),     currentY, w(), 20, (MidiChannel*) ch);
+               gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch);
 
        add(gch);
   resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop
@@ -216,7 +217,7 @@ gChannel *gColumn::addChannel(class Channel *ch)
 /* -------------------------------------------------------------------------- */
 
 
-void gColumn::deleteChannel(gChannel *gch)
+void gColumn::deleteChannel(geChannel *gch)
 {
        gch->hide();
        remove(gch);
@@ -228,7 +229,7 @@ void gColumn::deleteChannel(gChannel *gch)
         * parameter to skip the operation */
 
        for (int i=0; i<children(); i++) {
-               gch = (gChannel*) child(i);
+               gch = (geChannel*) child(i);
                gch->position(gch->x(), y()+(i*24));
        }
        size(w(), children() * 24 + 66);  // evil space for drag n drop
@@ -241,7 +242,7 @@ void gColumn::deleteChannel(gChannel *gch)
 
 void gColumn::__cb_addChannel()
 {
-       gLog("[gColumn::__cb_addChannel] index = %d\n", index);
+       gu_log("[gColumn::__cb_addChannel] index = %d\n", index);
        int type = openTypeMenu();
        if (type)
                glue_addChannel(index, type);
@@ -286,7 +287,7 @@ void gColumn::clear(bool full)
        else {
                while (children() >= 2) {  // skip "add new channel" btn
                        int i = children()-1;
-                       deleteChannel((gChannel*)child(i));
+                       deleteChannel((geChannel*)child(i));
                }
        }
 }
@@ -297,9 +298,9 @@ void gColumn::clear(bool full)
 
 Channel *gColumn::getChannel(int i)
 {
-  gChannel *gch = (gChannel*) child(i);
+  geChannel *gch = (geChannel*) child(i);
   if (gch->type == CHANNEL_SAMPLE)
-    return ((gSampleChannel*) child(i))->ch;
+    return ((geSampleChannel*) child(i))->ch;
   else
-    return ((gMidiChannel*) child(i))->ch;
+    return ((geMidiChannel*) child(i))->ch;
 }
index 93e8a1c14e02d9473935581a3584dfd1652bc8b5..bcaa2cae79f72f2f61f9d74190f7510a962112b1 100644 (file)
@@ -59,7 +59,7 @@ public:
         * add a new channel in this column and set the internal pointer
         * to channel to 'ch'. */
 
-       class gChannel *addChannel(class Channel *ch);
+       class geChannel *addChannel(class Channel *ch);
 
        /* handle */
 
@@ -73,7 +73,7 @@ public:
        /* deleteChannel
         * remove the channel 'gch' from this column. */
 
-       void deleteChannel(gChannel *gch);
+       void deleteChannel(geChannel *gch);
 
        /* refreshChannels
         * update channels' graphical statues. Called on each GUI cycle. */
index ed9f73841dc577b873ec24577da7a9be2bb12fbf..9ff5f25ede78a7341daad05cc7e3046538ad80f2 100644 (file)
@@ -27,7 +27,8 @@
 
 
 #include "../../core/graphics.h"
-#include "../../glue/glue.h"
+#include "../../glue/main.h"
+#include "../../glue/io.h"
 #include "ge_mixed.h"
 #include "ge_controller.h"
 
@@ -87,7 +88,7 @@ void gController::__cb_rewind()
 
 void gController::__cb_play()
 {
-       glue_startStopSeq();
+       glue_startStopSeq(true);
 }
 
 
@@ -96,7 +97,7 @@ void gController::__cb_play()
 
 void gController::__cb_recAction()
 {
-       glue_startStopActionRec();
+       glue_startStopActionRec(true);
 }
 
 
@@ -105,7 +106,7 @@ void gController::__cb_recAction()
 
 void gController::__cb_recInput()
 {
-       glue_startStopInputRec();
+       glue_startStopInputRec(true);
 }
 
 
@@ -114,7 +115,7 @@ void gController::__cb_recInput()
 
 void gController::__cb_metronome()
 {
-       glue_startStopMetronome();
+       glue_startStopMetronome(true);
 }
 
 
diff --git a/src/gui/elems/ge_envelopeChannel.cpp b/src/gui/elems/ge_envelopeChannel.cpp
deleted file mode 100644 (file)
index b6be16e..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_envelopeWidget
- *
- * Parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "../../core/channel.h"
-#include "../../core/recorder.h"
-#include "../../core/mixer.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "ge_keyboard.h"
-#include "ge_envelopeChannel.h"
-
-
-extern Mixer         G_Mixer;
-extern gdMainWindow *mainWin;
-
-
-gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l)
-       :       gActionWidget(x, y, 200, 80, pParent), l(l), type(type), range(range),
-               selectedPoint(-1), draggedPoint(-1)
-{
-       size(pParent->totalWidth, h());
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gEnvelopeChannel::~gEnvelopeChannel() {
-       clearPoints();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int py) {
-       point p;
-       p.frame  = frame;
-       p.iValue = iValue;
-       p.fValue = fValue;
-       p.x = px;
-       p.y = py;
-       points.push_back(p);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::updateActions() {
-       for (unsigned i=0; i<points.size(); i++)
-               points.at(i).x = points.at(i).frame / pParent->zoom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::draw() {
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT));
-
-       int pxOld = x()-3;
-       int pyOld = y()+1;
-       int pxNew = 0;
-       int pyNew = 0;
-
-       fl_color(COLOR_BG_2);
-
-       for (unsigned i=0; i<points.size(); i++) {
-
-               pxNew = points.at(i).x+x()-3;
-               pyNew = points.at(i).y+y();
-
-               if (selectedPoint == (int) i) {
-                       fl_color(COLOR_BD_1);
-                       fl_rectf(pxNew, pyNew, 7, 7);
-                       fl_color(COLOR_BG_2);
-               }
-               else
-                       fl_rectf(pxNew, pyNew, 7, 7);
-
-               if (i > 0)
-                       fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3);
-
-               pxOld = pxNew;
-               pyOld = pyNew;
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::handle(int e) {
-
-       /* Adding an action: no further checks required, just record it on frame
-        * mx*pParent->zoom. Deleting action is trickier: find the active
-        * point and derive from it the corresponding frame. */
-
-       int ret = 0;
-       int mx  = Fl::event_x()-x();  // mouse x
-       int my  = Fl::event_y()-y();  // mouse y
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       ret = 1;
-                       break;
-               }
-
-               case FL_MOVE: {
-                       selectedPoint = getSelectedPoint();
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH: {
-
-                       /* left click on point: drag
-                        * right click on point: delete
-                        * left click on void: add */
-
-                       if (Fl::event_button1()) {
-
-                               if (selectedPoint != -1) {
-                                       draggedPoint = selectedPoint;
-                               }
-                               else {
-
-                                       /* top & border fix */
-
-                                       if (my > h()-8) my = h()-8;
-                                       if (mx > pParent->coverX-x()) mx = pParent->coverX-x();
-
-                                       if (range == RANGE_FLOAT) {
-
-                                               /* if this is the first point ever, add other two points at the beginning
-                                                * and the end of the range */
-
-                                               if (points.size() == 0) {
-                                                       addPoint(0, 0, 1.0f, 0, 1);
-                                                       recorder::rec(pParent->chan->index, type, 0, 0, 1.0f);
-                                                       addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1);
-                                                       recorder::rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f);
-                                               }
-
-                                               /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */
-
-                                               int frame   = mx * pParent->zoom;
-                                               float value = (my - h() + 8) / (float) (1 - h() + 8);
-                                               addPoint(frame, 0, value, mx, my);
-                                               recorder::rec(pParent->chan->index, type, frame, 0, value);
-                                               recorder::sortActions();
-                                               sortPoints();
-                                       }
-                                       else {
-                                               /// TODO
-                                       }
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       redraw();
-                               }
-                       }
-                       else {
-
-                               /* right click on point 0 or point size-1 deletes the entire envelope */
-
-                               if (selectedPoint != -1) {
-                                       if (selectedPoint == 0 || (unsigned) selectedPoint == points.size()-1) {
-                                               recorder::clearAction(pParent->chan->index, type);
-                                               points.clear();
-                                       }
-                                       else {
-                                               recorder::deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false);
-                                               recorder::sortActions();
-                                               points.erase(points.begin() + selectedPoint);
-                                       }
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       redraw();
-                               }
-                       }
-
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-                       if (draggedPoint != -1) {
-
-                               if (points.at(draggedPoint).x == previousXPoint) {
-                                       //gLog("nothing to do\n");
-                               }
-                               else {
-                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
-
-                                       /* x edge correction */
-
-                                       if (newFrame < 0)
-                                               newFrame = 0;
-                                       else if (newFrame > G_Mixer.totalFrames)
-                                               newFrame = G_Mixer.totalFrames;
-
-                                       /* vertical line check */
-
-                                       int vp = verticalPoint(points.at(draggedPoint));
-                                       if (vp == 1)                     newFrame -= 256;
-                                       else if (vp == -1) newFrame += 256;
-
-                                       /*  delete previous point and record a new one */
-
-                                       recorder::deleteAction(pParent->chan->index,    points.at(draggedPoint).frame, type, false);
-
-                                       if (range == RANGE_FLOAT) {
-                                               float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8);
-                                               recorder::rec(pParent->chan->index, type, newFrame, 0, value);
-                                       }
-                                       else {
-                                               /// TODO
-                                       }
-
-                                       recorder::sortActions();
-                                       points.at(draggedPoint).frame = newFrame;
-                                       draggedPoint  = -1;
-                                       selectedPoint = -1;
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       if (draggedPoint != -1) {
-
-                               /* y constraint */
-
-                               if (my > h()-8)
-                                       points.at(draggedPoint).y = h()-8;
-                               else
-                               if (my < 1)
-                                       points.at(draggedPoint).y = 1;
-                               else
-                                       points.at(draggedPoint).y = my;
-
-                               /* x constraint
-                                * constrain the point between two ends (leftBorder-point, point-point,
-                                * point-rightBorder). First & last points cannot be shifted on x */
-
-                               if (draggedPoint == 0)
-                                       points.at(draggedPoint).x = x()-8;
-                               else
-                               if ((unsigned) draggedPoint == points.size()-1)
-                                       points.at(draggedPoint).x = pParent->coverX;
-                               else {
-                                       int prevPoint = points.at(draggedPoint-1).x;
-                                       int nextPoint = points.at(draggedPoint+1).x;
-                                       if (mx <= prevPoint)
-                                               points.at(draggedPoint).x = prevPoint;
-                                       else
-                                       if (mx >= nextPoint)
-                                               points.at(draggedPoint).x = nextPoint;
-                                       //else
-                                       //      points.at(draggedPoint).x = mx;
-                                       else {
-                                               if (pParent->gridTool->isOn())
-                                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mx)-1;
-                                               else
-                                                       points.at(draggedPoint).x = mx;
-                                       }
-                               }
-                               redraw();
-                       }
-
-                       ret = 1;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::verticalPoint(const point &p) {
-       for (unsigned i=0; i<points.size(); i++) {
-               if (&p == &points.at(i)) {
-                       if (i == 0 || i == points.size()-1)  // first or last point
-                               return 0;
-                       else {
-                               if (points.at(i-1).x == p.x)    // vertical with point[i-1]
-                                       return -1;
-                               else
-                               if (points.at(i+1).x == p.x)    // vertical with point[i+1]
-                                       return 1;
-                       }
-                       break;
-               }
-       }
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::sortPoints() {
-       for (unsigned i=0; i<points.size(); i++)
-               for (unsigned j=0; j<points.size(); j++)
-                       if (points.at(j).x > points.at(i).x)
-                               std::swap(points.at(j), points.at(i));
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gEnvelopeChannel::getSelectedPoint() {
-
-       /* point is a 7x7 dot */
-
-       for (unsigned i=0; i<points.size(); i++) {
-               if (Fl::event_x() >= points.at(i).x+x()-4  &&
-                               Fl::event_x() <= points.at(i).x+x()+4  &&
-                               Fl::event_y() >= points.at(i).y+y()    &&
-                               Fl::event_y() <= points.at(i).y+y()+7)
-               return i;
-       }
-       return -1;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gEnvelopeChannel::fill() {
-       points.clear();
-       for (unsigned i=0; i<recorder::global.size(); i++)
-               for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-                       recorder::action *a = recorder::global.at(i).at(j);
-                       if (a->type == type && a->chan == pParent->chan->index) {
-                               if (range == RANGE_FLOAT)
-                                       addPoint(
-                                               a->frame,                      // frame
-                                               0,                             // int value (unused)
-                                               a->fValue,                     // float value
-                                               a->frame / pParent->zoom,       // x
-                                               ((1-h()+8)*a->fValue)+h()-8);  // y = (b-a)x + a (line between two points)
-                               // else: TODO
-                       }
-               }
-
-}
diff --git a/src/gui/elems/ge_envelopeChannel.h b/src/gui/elems/ge_envelopeChannel.h
deleted file mode 100644 (file)
index 8afe11b..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_envelopeWidget
- *
- * parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef __GE_ENVELOPECHANNEL_H__
-#define __GE_ENVELOPECHANNEL_H__
-
-
-#include <vector>
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "../../utils/utils.h"
-#include "ge_actionWidget.h"
-
-
-using std::vector;
-
-
-class gEnvelopeChannel : public gActionWidget
-{
-       const char *l;      // internal label
-       int         type;   // type of action
-       int         range;
-
-       /* point
-        * a single dot in the graph. x = relative frame, y = relative value */
-
-       struct point {
-               int   frame;
-               int   iValue;
-               float fValue;
-               int   x;
-               int   y;
-       };
-
-       /* points
-        * array of points, filled by fillPoints() */
-
-       vector<point> points;
-
-       /* selectedPoint
-        * which point we are selecting? */
-
-       int selectedPoint;
-
-       /* draggedPoint
-        * which point we are dragging? */
-
-       int draggedPoint;
-
-       /* previousXPoint
-        * x coordinate of point at time t-1. Used to check effective shifts */
-
-       int previousXPoint;
-
-       void draw();
-
-       int handle(int e);
-
-       int getSelectedPoint();
-
-       void sortPoints();
-
-       /* verticalPoint
-        * check if two points form a vertical line. In that case the frame value
-        * would be the same and recorder would go crazy, so shift by a small value
-        * of frames to create a minimal fadein/fadeout level. Return 0: no
-        * vertical points; return 1: vertical with the next one, return -1: vertical
-        * with the previous one. */
-
-       int verticalPoint(const point &p);
-
-public:
-       gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l);
-       ~gEnvelopeChannel();
-
-       /* addPoint
-        * add a point made of frame+value to internal points[]. */
-
-       void addPoint(int frame, int iValue=0, float fValue=0.0f, int x=-1, int y=-1);
-
-       void updateActions();
-
-       /* fill
-        * parse recorder's stack and fill the widget with points. It's up to
-        * the caller to call this method as initialization. */
-
-       void fill();
-
-       inline void clearPoints() { points.clear(); }
-};
-
-#endif
index 5d5fd37f348f8d030a653f6e5a5d211bc43916d2..68a82287a013d1a4abf65c9e31f424847823440d 100644 (file)
 #include "../../core/patch_DEPR_.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
-#include "../../glue/glue.h"
+#include "../../glue/main.h"
+#include "../../glue/io.h"
 #include "../../utils/log.h"
 #include "../dialogs/gd_browser.h"
 #include "../dialogs/gd_mainWindow.h"
 #include "../dialogs/gd_editor.h"
 #include "../dialogs/gd_warnings.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
+#include "channel.h"
+#include "sampleChannel.h"
 #include "ge_keyboard.h"
 
 
@@ -101,7 +102,7 @@ void gKeyboard::init()
 /* -------------------------------------------------------------------------- */
 
 
-void gKeyboard::freeChannel(gChannel *gch)
+void gKeyboard::freeChannel(geChannel *gch)
 {
        gch->reset();
 }
@@ -110,7 +111,7 @@ void gKeyboard::freeChannel(gChannel *gch)
 /* -------------------------------------------------------------------------- */
 
 
-void gKeyboard::deleteChannel(gChannel *gch)
+void gKeyboard::deleteChannel(geChannel *gch)
 {
        for (unsigned i=0; i<columns.size(); i++) {
                int k = columns.at(i)->find(gch);
@@ -125,7 +126,7 @@ void gKeyboard::deleteChannel(gChannel *gch)
 /* -------------------------------------------------------------------------- */
 
 
-void gKeyboard::updateChannel(gChannel *gch)
+void gKeyboard::updateChannel(geChannel *gch)
 {
        gch->update();
 }
@@ -180,7 +181,7 @@ void gKeyboard::cb_addColumn(Fl_Widget *v, void *p)
 /* -------------------------------------------------------------------------- */
 
 
-gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build)
+geChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build)
 {
        gColumn *col = getColumnByIndex(colIndex);
 
@@ -191,10 +192,10 @@ gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build)
                __cb_addColumn();
                col = columns.back();
                col->setIndex(colIndex);
-               gLog("[gKeyboard::addChannel] created new column with index=%d\n", colIndex);
+               gu_log("[gKeyboard::addChannel] created new column with index=%d\n", colIndex);
        }
 
-       gLog("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
+       gu_log("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
        return col->addChannel(ch);
 }
 
@@ -223,6 +224,8 @@ gColumn *gKeyboard::getColumnByIndex(int index)
 
 /* -------------------------------------------------------------------------- */
 
+/* TODO - the following event handling for play, stop, rewind, start rec and
+so on should be moved to the proper widget: gdMainWindow or (better) geController. */
 
 int gKeyboard::handle(int e)
 {
@@ -254,13 +257,13 @@ int gKeyboard::handle(int e)
                                }
                                else if (Fl::event_key() == FL_Enter && !enterPressed) {
                                        enterPressed = true;
-                                       glue_startStopActionRec();
+                                       glue_startStopActionRec(false); // update gui
                                        ret = 1;
                                        break;
                                }
                                else if (Fl::event_key() == ' ' && !spacePressed) {
                                        spacePressed = true;
-                                       G_Mixer.running ? glue_stopSeq() : glue_startSeq(); // TODO - glue_startStopSeq, no core logic here
+          glue_startStopSeq(false);   // update gui
                                        ret = 1;
                                        break;
                                }
@@ -282,7 +285,7 @@ int gKeyboard::handle(int e)
 
                        for (unsigned i=0; i<columns.size(); i++)
                                for (int k=1; k<columns.at(i)->children(); k++)
-                                       ret &= ((gChannel*)columns.at(i)->child(k))->keyPress(e);
+                                       ret &= ((geChannel*)columns.at(i)->child(k))->keyPress(e);
                        break;
                }
        }
@@ -306,12 +309,12 @@ void gKeyboard::clear()
 /* -------------------------------------------------------------------------- */
 
 
-void gKeyboard::setChannelWithActions(gSampleChannel *gch)
+void gKeyboard::setChannelWithActions(geSampleChannel *gch)
 {
        if (gch->ch->hasActions)
-               gch->addActionButton();
+               gch->showActionButton();
        else
-               gch->delActionButton();
+               gch->hideActionButton();
 }
 
 
@@ -369,7 +372,7 @@ void gKeyboard::__cb_addColumn(int width)
        addColumnBtn->position(colxw + gap, y());
        redraw();
 
-       gLog("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n",
+       gu_log("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n",
                gc->getIndex(), width, columns.size(), addColumnBtn->x());
 
        /* recompute col indexes */
index 967758c5eccadb4317d0834be0dc9d722ad86b26..c5558b9a987512830e82dc9ce6eb24e80ef56304 100644 (file)
@@ -39,7 +39,7 @@
 #include <vector>
 #include "../elems/ge_column.h"
 #include "../../core/const.h"
-#include "../../utils/utils.h"
+#include "../../utils/fs.h"
 
 
 using std::vector;
@@ -87,12 +87,12 @@ public:
        void init();
 
        /* addChannel
-        * add a new channel to gChannels. Used by callbacks and during
-        * patch loading. Requires Channel (and not gChannel). If build is
+        * add a new channel to geChannels. Used by callbacks and during
+        * patch loading. Requires Channel (and not geChannel). If build is
         * set to true, also generate the corresponding column if column (index) does
         * not exist yet. */
 
-       gChannel *addChannel(int column, class Channel *ch, bool build=false);
+       class geChannel *addChannel(int column, class Channel *ch, bool build=false);
 
        /* addColumn
         * add a new column to the top of the stack. */
@@ -100,21 +100,21 @@ public:
        void addColumn(int width=380);
 
        /* deleteChannel
-        * delete a channel from gChannels<> where gChannel->ch == ch and remove
+        * delete a channel from geChannels<> where geChannel->ch == ch and remove
         * it from the stack. */
 
-       void deleteChannel(gChannel *gch);
+       void deleteChannel(geChannel *gch);
 
        /* freeChannel
-        * free a channel from gChannels<> where gChannel->ch == ch. No channels
+        * free a channel from geChannels<> where geChannel->ch == ch. No channels
         * are deleted */
 
-       void freeChannel(gChannel *gch);
+       void freeChannel(geChannel *gch);
 
        /* updateChannel
         * wrapper function to call gch->update(). */
 
-       void updateChannel(gChannel *gch);
+       void updateChannel(geChannel *gch);
 
        /* organizeColumns
         * reorganize columns layout by removing empty gaps. */
@@ -144,7 +144,7 @@ public:
        /* setChannelWithActions
         * add 'R' button if channel has actions, and set recorder to active. */
 
-       void setChannelWithActions(class gSampleChannel *gch);
+       void setChannelWithActions(class geSampleChannel *gch);
 
        /* printChannelMessage
         * given any output by glue_loadChannel, print the message on screen
diff --git a/src/gui/elems/ge_midiChannel.cpp b/src/gui/elems/ge_midiChannel.cpp
deleted file mode 100644 (file)
index bd139c3..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../../core/pluginHost.h"
-#include "../../core/mixer.h"
-#include "../../core/conf.h"
-#include "../../core/patch_DEPR_.h"
-#include "../../core/graphics.h"
-#include "../../core/channel.h"
-#include "../../core/wave.h"
-#include "../../core/sampleChannel.h"
-#include "../../core/midiChannel.h"
-#include "../../glue/channel.h"
-#include "../../glue/glue.h"
-#include "../../utils/gui_utils.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "../dialogs/gd_keyGrabber.h"
-#include "../dialogs/gd_midiInput.h"
-#include "../dialogs/gd_editor.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "../dialogs/gd_warnings.h"
-#include "../dialogs/gd_browser.h"
-#include "../dialogs/gd_keyGrabber.h"
-#include "../dialogs/gd_midiOutput.h"
-#include "ge_keyboard.h"
-#include "ge_midiChannel.h"
-#include "ge_channel.h"
-#include "ge_sampleChannel.h"
-#include "../dialogs/gd_pluginList.h"
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch_DEPR_   G_Patch_DEPR_;
-extern gdMainWindow *mainWin;
-
-
-gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch)
-       : gChannel(X, Y, W, H, CHANNEL_MIDI), ch(ch)
-{
-       begin();
-
-#if defined(WITH_VST)
-  int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
-#else
-       int delta = 96; // (4 widgets * 20) + (4 paddings * 4)
-#endif
-
-       button     = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
-       mainButton = new gMidiChannelButton(button->x()+button->w()+4, y(), w() - delta, 20, "-- MIDI --");
-       mute       = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo       = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
-#if defined(WITH_VST)
-       fx         = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol        = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
-#else
-       vol        = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
-#endif
-
-       end();
-
-  resizable(mainButton);
-
-       update();
-
-       button->callback(cb_button, (void*)this);
-       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
-
-#ifdef WITH_VST
-       fx->callback(cb_openFxWindow, (void*)this);
-#endif
-
-       mute->type(FL_TOGGLE_BUTTON);
-       mute->callback(cb_mute, (void*)this);
-
-       solo->type(FL_TOGGLE_BUTTON);
-       solo->callback(cb_solo, (void*)this);
-
-       mainButton->callback(cb_openMenu, (void*)this);
-
-       vol->callback(cb_changeVol, (void*)this);
-
-       ch->guiChannel = this;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::cb_button      (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_button(); }
-void gMidiChannel::cb_mute        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_mute(); }
-void gMidiChannel::cb_solo        (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_solo(); }
-void gMidiChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openMenu(); }
-void gMidiChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_changeVol(); }
-#ifdef WITH_VST
-void gMidiChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openFxWindow(); }
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_mute()
-{
-       glue_setMute(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_solo()
-{
-       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_changeVol()
-{
-       glue_setChanVol(ch, vol->value());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-void gMidiChannel::__cb_openFxWindow()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
-}
-#endif
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_button()
-{
-       if (button->value())
-               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::__cb_openMenu()
-{
-       Fl_Menu_Item rclick_menu[] = {
-               {"Edit actions..."},                        // 0
-               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 1
-                       {"All"},                                  // 2
-                       {0},                                      // 3
-               {"Setup keyboard input..."},                // 5
-               {"Setup MIDI input..."},                    // 6
-               {"Setup MIDI output..."},                   // 7
-               {"Clone channel"},                          // 8
-               {"Delete channel"},                         // 9
-               {0}
-       };
-
-       /* no 'clear actions' if there are no actions */
-
-       if (!ch->hasActions)
-               rclick_menu[1].deactivate();
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(GUI_FONT_SIZE_BASE);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-       if (strcmp(m->label(), "Delete channel") == 0) {
-               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
-                       return;
-               glue_deleteChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Clone channel") == 0) {
-               glue_cloneChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
-               gu_openSubWindow(mainWin, new gdKeyGrabber(ch), 0);
-               //new gdKeyGrabber(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "All") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-                       return;
-               recorder::clearChan(ch->index);
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit actions...") == 0) {
-               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
-               //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0);
-               gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0);
-               return;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::refresh()
-{
-       setColorsByStatus(ch->status, ch->recStatus);
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::reset()
-{
-       mainButton->setDefaultMode("-- MIDI --");
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::update()
-{
-       if (ch->midiOut) {
-               char tmp[32];
-               sprintf(tmp, "-- MIDI (channel %d) --", ch->midiOutChan+1);
-               mainButton->copy_label(tmp);
-       }
-       else
-               mainButton->label("-- MIDI --");
-
-       vol->value(ch->volume);
-       mute->value(ch->mute);
-       solo->value(ch->solo);
-
-       mainButton->setKey(ch->key);
-
-#ifdef WITH_VST
-       fx->full = ch->plugins.size() > 0;
-       fx->redraw();
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gMidiChannel::resize(int X, int Y, int W, int H)
-{
-  gChannel::resize(X, Y, W, H);
-
-       /* this stuff makes sense only with FX button available. Do nothing
-        * otherwise */
-
-#ifdef WITH_VST
-       if (w() < BREAK_FX) {
-               fx->hide();
-
-               mainButton->size(w() - (BREAK_DELTA - BREAK_UNIT), mainButton->h());
-       }
-       else {
-               fx->show();
-               mainButton->size(w() - BREAK_DELTA, mainButton->h());
-       }
-       mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-       solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-
-       gChannel::init_sizes();
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gMidiChannel::keyPress(int e)
-{
-       return handleKey(e, ch->key);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gMidiChannelButton::gMidiChannelButton(int x, int y, int w, int h, const char *l)
-       : gChannelButton(x, y, w, h, l) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gMidiChannelButton::handle(int e)
-{
-       // MIDI drag-n-drop does nothing so far.
-       return gClick::handle(e);
-}
diff --git a/src/gui/elems/ge_midiChannel.h b/src/gui/elems/ge_midiChannel.h
deleted file mode 100644 (file)
index ac1141a..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_midiChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_MIDI_CHANNEL_H
-#define GE_MIDI_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_channel.h"
-#include "ge_channelButton.h"
-#include "ge_mixed.h"
-
-
-class gMidiChannel : public gChannel
-{
-private:
-
-       static void cb_button        (Fl_Widget *v, void *p);
-       static void cb_mute          (Fl_Widget *v, void *p);
-       static void cb_solo          (Fl_Widget *v, void *p);
-       static void cb_openMenu      (Fl_Widget *v, void *p);
-       static void cb_changeVol     (Fl_Widget *v, void *p);
-#ifdef WITH_VST
-       static void cb_openFxWindow  (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_mute        ();
-       inline void __cb_solo        ();
-       inline void __cb_changeVol   ();
-       inline void __cb_button      ();
-       inline void __cb_openMenu    ();
-       inline void __cb_readActions ();
-#ifdef WITH_VST
-       inline void __cb_openFxWindow();
-#endif
-
-public:
-
-       gMidiChannel(int x, int y, int w, int h,  class MidiChannel *ch);
-
-       void reset   ();
-       void update  ();
-       void refresh ();
-       int  keyPress(int event);
-       void resize  (int x, int y, int w, int h);
-
-       class MidiChannel *ch;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gMidiChannelButton : public gChannelButton
-{
-public:
-       gMidiChannelButton(int x, int y, int w, int h, const char *l=0);
-       int handle(int e);
-};
-
-
-#endif
index 9057f3f014a1921ccd1e54b0762a23766038c24d..8c201018a84ebccfd0586ae0725ec79993f5c1a4 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include "ge_midiIoTools.h"
 #include "ge_mixed.h"
+#include "ge_midiIoTools.h"
+
+
+extern KernelMidi  G_KernelMidi;
 
 
-gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param)
+gLearner::gLearner(int X, int Y, int W, const char *l, KernelMidi::cb_midiLearn *cb,
+               uint32_t *param)
        : Fl_Group(X, Y, W, 20),
                callback(cb),
                param   (param)
@@ -98,8 +102,8 @@ void gLearner::__cb_button() {
                cbData *data  = (cbData*) malloc(sizeof(cbData));
                data->window  = (gdMidiInput*) parent();  // parent = gdMidiGrabberChannel
                data->learner = this;
-               kernelMidi::startMidiLearn(callback, (void*)data);
+               G_KernelMidi.startMidiLearn(callback, (void*)data);
        }
        else
-               kernelMidi::stopMidiLearn();
+               G_KernelMidi.stopMidiLearn();
 }
index 2a795e1d25d26c2eb99db959954d8cddd323ac7c..071293746839afd6fdd93a5b0b7586dcd1e2f648 100644 (file)
 #define GE_LEARNER_H
 
 
-#include <FL/Fl.H>
 #include <FL/Fl_Group.H>
 #include "../../core/kernelMidi.h"
 #include "../dialogs/gd_midiInput.h"
 
 
+extern KernelMidi G_KernelMidi;
+
+
 class gLearner : public Fl_Group
 {
 private:
@@ -46,7 +48,7 @@ private:
         * uint32_t msg - MIDI message
         * void   *data - extra data */
 
-       kernelMidi::cb_midiLearn *callback;
+       KernelMidi::cb_midiLearn *callback;
 
        class gBox    *text;
        class gClick  *value;
@@ -64,7 +66,7 @@ public:
 
        uint32_t *param;
 
-       gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param);
+       gLearner(int x, int y, int w, const char *l, KernelMidi::cb_midiLearn *cb, uint32_t *param);
 
        void updateValue();
 };
index 60abf9e924b90190aae1aa785aa704e1057aee7e..0969a8a1b5bc441c4447b6ef7f9b4e10af43fef2 100644 (file)
@@ -34,7 +34,7 @@
 #include "../../core/recorder.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../dialogs/gd_mainWindow.h"
 #include "ge_mixed.h"
 
@@ -452,7 +452,7 @@ gResizerBar::gResizerBar(int X,int Y,int W,int H, bool vertical)
 /*
 gResizerBar::~gResizerBar()
 {
-  gLog("------ resizerbar %p destroyed\n", (void*)this);
+  gu_log("------ resizerbar %p destroyed\n", (void*)this);
 }
 */
 
index b41be44d140a21d089cd704b71ff62280eea7187..d454497e29da87affc386f3757913abf44028d9e 100644 (file)
@@ -120,6 +120,7 @@ public:
 /* gButton
  * exactly as gClick but with a unique id inside of it. Used for the buttons in
  * channels and for FXs. */
+ /* TODO - is this really useful? */
 
 class gButton : public gClick
 {
index 27afbeafaa78d0a417dbc3f852bcc0176a359505..4a6915b8770095757cc7d54b070d129bfdded3d7 100644 (file)
@@ -27,7 +27,7 @@
  * -------------------------------------------------------------------------- */
 
 
-#include "../../utils/gui_utils.h"
+#include "../../utils/gui.h"
 #include "../../core/graphics.h"
 #include "../../core/sampleChannel.h"
 #include "../../core/const.h"
diff --git a/src/gui/elems/ge_muteChannel.cpp b/src/gui/elems/ge_muteChannel.cpp
deleted file mode 100644 (file)
index 7b996b8..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_muteChannel
- * a widget that represents mute actions inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include "../../core/recorder.h"
-#include "../../core/mixer.h"
-#include "../../core/channel.h"
-#include "../../glue/glue.h"
-#include "../../utils/log.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "ge_keyboard.h"
-#include "ge_actionWidget.h"
-#include "ge_muteChannel.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-
-
-gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent)
- : gActionWidget(x, y, 200, 80, pParent), draggedPoint(-1), selectedPoint(-1)
-{
-       size(pParent->totalWidth, h());
-       extractPoints();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::draw() {
-
-       baseDraw();
-
-       /* print label */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 12);
-       fl_draw("mute", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
-
-       /* draw "on" and "off" labels. Must stay in background */
-
-       fl_color(COLOR_BG_1);
-       fl_font(FL_HELVETICA, 9);
-       fl_draw("on",  x()+4, y(),        w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-       fl_draw("off", x()+4, y()+h()-14, w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-
-       /* draw on-off points. On = higher rect, off = lower rect. It always
-        * starts with a note_off */
-
-       fl_color(COLOR_BG_2);
-
-       int pxOld = x()+1;
-       int pxNew = 0;
-       int py    = y()+h()-5;
-       int pyDot = py-6;
-
-       for (unsigned i=0; i<points.size(); i++) {
-
-               /* next px */
-
-               pxNew = points.at(i).x+x();
-
-               /* draw line from pxOld to pxNew.
-                * i % 2 == 0: first point, mute_on
-                * i % 2 != 0: second point, mute_off */
-
-               fl_line(pxOld, py, pxNew, py);
-               pxOld = pxNew;
-
-               py = i % 2 == 0 ? y()+4 : y()+h()-5;
-
-               /* draw dots (handles) */
-
-               fl_line(pxNew, y()+h()-5, pxNew, y()+4);
-
-               if (selectedPoint == (int) i) {
-                       fl_color(COLOR_BD_1);
-                       fl_rectf(pxNew-3, pyDot, 7, 7);
-                       fl_color(COLOR_BG_2);
-               }
-               else
-                       fl_rectf(pxNew-3, pyDot, 7, 7);
-       }
-
-       /* last section */
-
-       py = y()+h()-5;
-       fl_line(pxNew+3, py, pParent->coverX+x()-1, py);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::extractPoints() {
-
-       points.clear();
-
-       /* actions are already sorted by recorder::sortActions() */
-
-       for (unsigned i=0; i<recorder::frames.size(); i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-                       if (recorder::global.at(i).at(j)->chan == pParent->chan->index) {
-                               if (recorder::global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) {
-                                       point p;
-                                       p.frame = recorder::frames.at(i);
-                                       p.type  = recorder::global.at(i).at(j)->type;
-                                       p.x     = p.frame / pParent->zoom;
-                                       points.push_back(p);
-                                       //gLog("[gMuteChannel::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame);
-                               }
-                       }
-               }
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gMuteChannel::updateActions() {
-       for (unsigned i=0; i<points.size(); i++)
-               points.at(i).x = points.at(i).frame / pParent->zoom;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gMuteChannel::handle(int e) {
-
-       int ret = 0;
-       int mouseX = Fl::event_x()-x();
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       ret = 1;
-                       break;
-               }
-
-               case FL_MOVE: {
-                       selectedPoint = getSelectedPoint();
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-                       redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_PUSH: {
-
-                       /* left click on point: drag
-                        * right click on point: delete
-                        * left click on void: add */
-
-                       if (Fl::event_button1())  {
-
-                               if (selectedPoint != -1) {
-                                       draggedPoint   = selectedPoint;
-                                       previousXPoint = points.at(selectedPoint).x;
-                               }
-                               else {
-
-                                       /* click on the grey area leads to nowhere */
-
-                                       if (mouseX > pParent->coverX) {
-                                               ret = 1;
-                                               break;
-                                       }
-
-                                       /* click in the middle of a long mute_on (between two points): new actions
-                                        * must be added in reverse: first mute_off then mute_on. Let's find the
-                                        * next point from here. */
-
-                                       unsigned nextPoint = points.size();
-                                       for (unsigned i=0; i<points.size(); i++) {
-                                               if (mouseX < points.at(i).x) {
-                                                       nextPoint = i;
-                                                       break;
-                                               }
-                                       }
-
-                                       /* next point odd = mute_on [click here] mute_off
-                                        * next point even = mute_off [click here] mute_on */
-
-                                       int frame_a = mouseX * pParent->zoom;
-                                       int frame_b = frame_a+2048;
-
-                                       if (pParent->gridTool->isOn()) {
-                                               frame_a = pParent->gridTool->getSnapFrame(mouseX);
-                                               frame_b = pParent->gridTool->getSnapFrame(mouseX + pParent->gridTool->getCellSize());
-
-                                               /* with snap=on a point can fall onto another */
-
-                                               if (pointCollides(frame_a) || pointCollides(frame_b)) {
-                                                       ret = 1;
-                                                       break;
-                                               }
-                                       }
-
-                                       /* ensure frame parity */
-
-                                       if (frame_a % 2 != 0) frame_a++;
-                                       if (frame_b % 2 != 0) frame_b++;
-
-                                       /* avoid overflow: frame_b must be within the sequencer range. In that
-                                        * case shift the ON-OFF block */
-
-                                       if (frame_b >= G_Mixer.totalFrames) {
-                                               frame_b = G_Mixer.totalFrames;
-                                               frame_a = frame_b-2048;
-                                       }
-
-                                       if (nextPoint % 2 != 0) {
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_a);
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_b);
-                                       }
-                                       else {
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEON,  frame_a);
-                                               recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_b);
-                                       }
-                                       recorder::sortActions();
-
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       extractPoints();
-                                       redraw();
-                               }
-                       }
-                       else {
-
-                               /* delete points pair */
-
-                               if (selectedPoint != -1) {
-
-                                       unsigned a;
-                                       unsigned b;
-
-                                       if (points.at(selectedPoint).type == ACTION_MUTEOFF) {
-                                               a = selectedPoint-1;
-                                               b = selectedPoint;
-                                       }
-                                       else {
-                                               a = selectedPoint;
-                                               b = selectedPoint+1;
-                                       }
-
-                                       //gLog("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n",
-                                       //              a, b, points.at(a).frame, points.at(b).frame);
-
-                                       recorder::deleteAction(pParent->chan->index, points.at(a).frame,        points.at(a).type, false); // false = don't check vals
-                                       recorder::deleteAction(pParent->chan->index,    points.at(b).frame,     points.at(b).type, false); // false = don't check vals
-                                       recorder::sortActions();
-
-                                       mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow
-                                       extractPoints();
-                                       redraw();
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-
-                       if (draggedPoint != -1) {
-
-                               if (points.at(draggedPoint).x == previousXPoint) {
-                                       //gLog("nothing to do\n");
-                               }
-                               else {
-
-                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
-
-                                       recorder::deleteAction(
-                                                       pParent->chan->index,
-                                                       points.at(draggedPoint).frame,
-                                                       points.at(draggedPoint).type,
-                                                       false);  // don't check values
-
-                                       recorder::rec(
-                                                       pParent->chan->index,
-                                                       points.at(draggedPoint).type,
-                                                       newFrame);
-
-                                       recorder::sortActions();
-
-                                       points.at(draggedPoint).frame = newFrame;
-                               }
-                       }
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       if (draggedPoint != -1) {
-
-                               /* constrain the point between two ends (leftBorder-point,
-                                * point-point, point-rightBorder) */
-
-                               int prevPoint;
-                               int nextPoint;
-
-                               if (draggedPoint == 0) {
-                                       prevPoint = 0;
-                                       nextPoint = points.at(draggedPoint+1).x - 1;
-                                       if (pParent->gridTool->isOn())
-                                               nextPoint -= pParent->gridTool->getCellSize();
-                               }
-                               else
-                               if ((unsigned) draggedPoint == points.size()-1) {
-                                       prevPoint = points.at(draggedPoint-1).x + 1;
-                                       nextPoint = pParent->coverX-x();
-                                       if (pParent->gridTool->isOn())
-                                               prevPoint += pParent->gridTool->getCellSize();
-                               }
-                               else {
-                                       prevPoint = points.at(draggedPoint-1).x + 1;
-                                       nextPoint = points.at(draggedPoint+1).x - 1;
-                                       if (pParent->gridTool->isOn()) {
-                                               prevPoint += pParent->gridTool->getCellSize();
-                                               nextPoint -= pParent->gridTool->getCellSize();
-                                       }
-                               }
-
-                               if (mouseX <= prevPoint)
-                                       points.at(draggedPoint).x = prevPoint;
-                               else
-                               if (mouseX >= nextPoint)
-                                       points.at(draggedPoint).x = nextPoint;
-                               else
-                               if (pParent->gridTool->isOn())
-                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mouseX)-1;
-                               else
-                                       points.at(draggedPoint).x = mouseX;
-
-                               redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-       }
-
-
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gMuteChannel::pointCollides(int frame) {
-       for (unsigned i=0; i<points.size(); i++)
-               if (frame == points.at(i).frame)
-                       return true;
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gMuteChannel::getSelectedPoint() {
-
-       /* point is a 7x7 dot */
-
-       for (unsigned i=0; i<points.size(); i++) {
-               if (Fl::event_x() >= points.at(i).x+x()-3 &&
-                               Fl::event_x() <= points.at(i).x+x()+3)
-               return i;
-       }
-       return -1;
-}
diff --git a/src/gui/elems/ge_muteChannel.h b/src/gui/elems/ge_muteChannel.h
deleted file mode 100644 (file)
index 2e74453..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_muteChannel
- * a widget representing mute actions inside the action editor.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GE_MUTECHANNEL_H
-#define GE_MUTECHANNEL_H
-
-
-#include <vector>
-#include <FL/Fl.H>
-#include <FL/Fl_Widget.H>
-#include <FL/fl_draw.H>
-#include "../../utils/utils.h"
-#include "ge_actionWidget.h"
-
-
-using std::vector;
-
-
-class gMuteChannel : public gActionWidget
-{
-private:
-
-       /* point
-        * a single dot in the graph. */
-
-       struct point {
-               int  frame;
-               char type;
-               int  x;
-       };
-
-       /* points
-        * array of on/off points, in frames */
-
-       vector<point> points;
-
-       /* draggedPoint
-        * which point we are dragging? */
-
-       int draggedPoint;
-
-       /* selectedPoint
-        * which point we are selecting? */
-
-       int selectedPoint;
-
-       /* previousXPoint
-        * x coordinate of point at time t-1. Used to check effective shifts */
-
-       int previousXPoint;
-
-       /* extractPoints
-        * va a leggere l'array di azioni di Recorder ed estrae tutti i punti
-        * interessanti mute_on o mute_off. Li mette poi nel vector points. */
-       void extractPoints();
-
-       /* getSelectedPoint
-        * ritorna l'indice di points[] in base al punto selezionato (quello
-        * con il mouse hover). Ritorna -1 se non trova niente. */
-       int getSelectedPoint();
-
-       /* pointCollides
-        * true if a point collides with another. Used while adding new points
-        * with snap active.*/
-
-       bool pointCollides(int frame);
-
-public:
-
-       gMuteChannel(int x, int y, class gdActionEditor *pParent);
-       void draw();
-       int  handle(int e);
-
-       /* updateActions
-        * calculates new points affected by the zoom. Call this one after
-        * each zoom update. */
-
-       void updateActions();
-};
-
-#endif
diff --git a/src/gui/elems/ge_pianoRoll.cpp b/src/gui/elems/ge_pianoRoll.cpp
deleted file mode 100644 (file)
index bd3dd5b..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_pianoRoll
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#include <FL/fl_draw.H>
-#include "../../core/channel.h"
-#include "../../core/midiChannel.h"
-#include "../../core/const.h"
-#include "../../core/kernelMidi.h"
-#include "../../core/conf.h"
-#include "../../utils/log.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "ge_pianoRoll.h"
-
-
-extern gdMainWindow *mainWin;
-extern Mixer         G_Mixer;
-extern Conf             G_Conf;
-
-
-gPianoRollContainer::gPianoRollContainer(int x, int y, class gdActionEditor *pParent)
- : Fl_Scroll(x, y, 200, 422), pParent(pParent)
-{
-       size(pParent->totalWidth, G_Conf.pianoRollH);
-       pianoRoll = new gPianoRoll(x, y, pParent->totalWidth, pParent);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gPianoRollContainer::~gPianoRollContainer() {
-       clear();
-       G_Conf.pianoRollH = h();
-       G_Conf.pianoRollY = pianoRoll->y();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRollContainer::updateActions() {
-       pianoRoll->updateActions();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRollContainer::draw() {
-
-       pianoRoll->size(this->w(), pianoRoll->h());  /// <--- not optimal
-
-       /* clear background */
-
-       fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
-
-       /* clip pianoRoll to pianoRollContainer size */
-
-       fl_push_clip(x(), y(), w(), h());
-       draw_child(*pianoRoll);
-       fl_pop_clip();
-
-       fl_color(COLOR_BD_0);
-       fl_line_style(0);
-       fl_rect(x(), y(), pParent->totalWidth, h());
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gPianoRoll::gPianoRoll(int X, int Y, int W, class gdActionEditor *pParent)
- : gActionWidget(X, Y, W, 40, pParent)
-{
-       resizable(NULL);                      // don't resize children (i.e. pianoItem)
-       size(W, (MAX_NOTES+1) * CELL_H);      // 128 MIDI channels * 15 px height
-
-       if (G_Conf.pianoRollY == -1)
-               position(x(), y()-(h()/2));  // center
-       else
-               position(x(), G_Conf.pianoRollY);
-
-       drawSurface1();
-       drawSurface2();
-
-       /* add actions when the window is opened. Position is zoom-based. MIDI
-        * actions come always in pair: start + end. */
-
-       recorder::sortActions();
-
-       recorder::action *a2   = NULL;
-       recorder::action *prev = NULL;
-
-       for (unsigned i=0; i<recorder::frames.size(); i++) {
-               for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-
-                       /* don't show actions > than the grey area */
-                       /** FIXME - can we move this to the outer cycle? */
-
-                       if (recorder::frames.at(i) > G_Mixer.totalFrames)
-                               continue;
-
-                       recorder::action *a1 = recorder::global.at(i).at(j);
-
-                       if (a1->chan != pParent->chan->index)
-                               continue;
-
-                       if (a1->type == ACTION_MIDI) {
-
-                               /* if this action is == to previous one: skip it, we have already
-                                * checked it */
-
-                               if (a1 == prev) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was previous\n");
-                                       continue;
-                               }
-
-                               /* extract MIDI infos from a1: if is note off skip it, we are looking
-                                * for note on only */
-
-                               int a1_type = kernelMidi::getB1(a1->iValue);
-                               int a1_note = kernelMidi::getB2(a1->iValue);
-                               int a1_velo = kernelMidi::getB3(a1->iValue);
-
-                               if (a1_type == 0x80) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was note off\n");
-                                       continue;
-                               }
-
-                               /* search for the next action. Must have: same channel, ACTION_MIDI, greater
-                                * than a1->frame and with MIDI properties of note_off (0x80), same note
-                                * of a1, same velocity of a1 */
-
-                               recorder::getNextAction(
-                                               a1->chan,
-                                               ACTION_MIDI,
-                                               a1->frame,
-                                               &a2,
-                                               kernelMidi::getIValue(0x80, a1_note, a1_velo));
-
-                               /* next action note off found: add a new gPianoItem to piano roll */
-
-                               if (a2) {
-                                       //gLog("[gPianoRoll] ACTION_MIDI pair found, frame_a=%d frame_b=%d, note_a=%d, note_b=%d, type_a=%d, type_b=%d\n",
-                                       //      a1->frame, a2->frame, kernelMidi::getNoteValue(a1->iValue), kernelMidi::getNoteValue(a2->iValue),
-                                       //      kernelMidi::getNoteOnOff(a1->iValue), kernelMidi::getNoteOnOff(a2->iValue));
-                                       new gPianoItem(0, 0, x(), y()+3, a1, a2, pParent);
-                                       prev = a2;
-                                       a2 = NULL;
-                               }
-                               else
-                                       gLog("[gPianoRoll] recorder didn't find action!\n");
-
-                       }
-               }
-       }
-
-       end();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::drawSurface1() {
-
-       surface1 = fl_create_offscreen(40, h());
-       fl_begin_offscreen(surface1);
-
-       /* warning: only w() and h() come from this widget, x and y coordinates
-        * are absolute, since we are writing in a memory chunk */
-
-       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
-
-       fl_line_style(FL_DASH, 0, NULL);
-       fl_font(FL_HELVETICA, 11);
-
-       int octave = 9;
-
-       for (int i=1; i<=MAX_NOTES+1; i++) {
-
-               /* print key note label. C C# D D# E F F# G G# A A# B */
-
-               char note[6];
-               int  step = i % 12;
-
-               switch (step) {
-                       case 1:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dG", octave);
-                               break;
-                       case 2:
-                               sprintf(note, "%dF#", octave);
-                               break;
-                       case 3:
-                               sprintf(note, "%dF", octave);
-                               break;
-                       case 4:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dE", octave);
-                               break;
-                       case 5:
-                               sprintf(note, "%dD#", octave);
-                               break;
-                       case 6:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dD", octave);
-                               break;
-                       case 7:
-                               sprintf(note, "%dC#", octave);
-                               break;
-                       case 8:
-                               sprintf(note, "%dC", octave);
-                               break;
-                       case 9:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dB", octave);
-                               break;
-                       case 10:
-                               sprintf(note, "%dA#", octave);
-                               break;
-                       case 11:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               sprintf(note, "%dA", octave);
-                               break;
-                       case 0:
-                               sprintf(note, "%dG#", octave);
-                               octave--;
-                               break;
-               }
-
-               fl_color(fl_rgb_color(54, 54, 54));
-               fl_draw(note, 4, ((i-1)*CELL_H)+1, 30, CELL_H, (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
-
-               /* print horizontal line */
-
-               if (i < 128)
-                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
-       }
-
-       fl_line_style(0);
-       fl_end_offscreen();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::drawSurface2() {
-       surface2 = fl_create_offscreen(40, h());
-       fl_begin_offscreen(surface2);
-       fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN);
-       fl_color(fl_rgb_color(54, 54, 54));
-       fl_line_style(FL_DASH, 0, NULL);
-       for (int i=1; i<=MAX_NOTES+1; i++) {
-               int  step = i % 12;
-               switch (step) {
-                       case 1:
-                       case 4:
-                       case 6:
-                       case 9:
-                       case 11:
-                               fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30);
-                               break;
-               }
-               if (i < 128) {
-                       fl_color(fl_rgb_color(54, 54, 54));
-                       fl_line(0, i*CELL_H, 40, +i*CELL_H);
-               }
-       }
-       fl_line_style(0);
-       fl_end_offscreen();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::draw() {
-
-       fl_copy_offscreen(x(), y(), 40, h(), surface1, 0, 0);
-
-#if defined(__APPLE__)
-       for (int i=36; i<pParent->totalWidth; i+=36) /// TODO: i < pParent->coverX is faster
-               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 1, 0);
-#else
-       for (int i=40; i<pParent->totalWidth; i+=40) /// TODO: i < pParent->coverX is faster
-               fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 0, 0);
-#endif
-
-       baseDraw(false);
-       draw_children();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gPianoRoll::handle(int e) {
-
-       int ret = Fl_Group::handle(e);
-
-       switch (e) {
-               case FL_PUSH:   {
-
-                       /* avoid click on grey area */
-
-                       if (Fl::event_x() >= pParent->coverX) {
-                               ret = 1;
-                               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 */
-
-                               int ax = Fl::event_x();
-                               int ay = Fl::event_y();
-
-                               /* vertical snap */
-
-                               int edge = (ay-y()-3) % 15;
-                               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 (!onItem(ax, ay-y()-3)) {
-                                       int greyover = ax+20 - pParent->coverX-x();
-                                       if (greyover > 0)
-                                               ax -= greyover;
-                                       add(new gPianoItem(ax, ay, ax-x(), ay-y()-3, NULL, NULL, pParent));
-                                       redraw();
-                               }
-                       }
-                       ret = 1;
-                       break;
-               }
-               case FL_DRAG:   {
-
-                       if (Fl::event_button3()) {
-
-                               gPianoRollContainer *prc = (gPianoRollContainer*) parent();
-                               position(x(), Fl::event_y() - push_y);
-
-                               if (y() > prc->y())
-                                       position(x(), prc->y());
-                               else
-                               if (y() < prc->y()+prc->h()-h())
-                                       position(x(), prc->y()+prc->h()-h());
-
-                               prc->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-               case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoRoll::updateActions() {
-
-       /* when zooming, don't delete and re-add actions, just MOVE them. This
-        * function shifts the action by a zoom factor. Those singlepress are
-        * stretched, as well */
-
-       gPianoItem *i;
-       for (int k=0; k<children(); k++) {
-               i = (gPianoItem*) child(k);
-
-               //gLog("found point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
-
-               int newX = x() + (i->getFrame_a() / pParent->zoom);
-               int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom);
-               if (newW < 8)
-                       newW = 8;
-               i->resize(newX, i->y(), newW, i->h());
-               i->redraw();
-
-               //gLog("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gPianoRoll::onItem(int rel_x, int rel_y) {
-
-       if (!pParent->chan->hasActions)
-               return false;
-
-       int note = MAX_NOTES - (rel_y / CELL_H);
-
-       int n = children();
-       for (int i=0; i<n; i++) {   // no scrollbars to skip
-
-               gPianoItem *p = (gPianoItem*) child(i);
-               if (p->getNote() != note)
-                       continue;
-
-               /* when 2 segments overlap?
-                * start = the highest value between the two starting points
-                * end   = the lowest value between the two ending points
-                * if start < end then there's an overlap of end-start pixels. We
-                * also add 1 px to the edges in order to gain some space:
-                * [   ][   ]  ---> no
-                * [   ] [   ] ---> yes! */
-
-               int start = p->x() > rel_x ? p->x() : rel_x-1;
-               int end   = p->x()+p->w() < rel_x + 20 ? p->x()+p->w() : rel_x + 21;
-               if (start < end)
-                       return true;
-       }
-       return false;
-}
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gPianoItem::gPianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *_a, recorder::action *_b, gdActionEditor *pParent)
-       : Fl_Box  (X, Y, 20, gPianoRoll::CELL_H-5),
-         a       (_a),
-         b       (_b),
-               pParent (pParent),
-               selected(false),
-               event_a (0x00),
-               event_b (0x00),
-               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());
-       }
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-bool gPianoItem::overlap() {
-
-       /* when 2 segments overlap?
-        * start = the highest value between the two starting points
-        * end   = the lowest value between the two ending points
-        * if start < end then there's an overlap of end-start pixels. */
-
-       gPianoRoll *pPiano = (gPianoRoll*) parent();
-
-       for (int i=0; i<pPiano->children(); i++) {
-
-               gPianoItem *pItem = (gPianoItem*) pPiano->child(i);
-
-               /* don't check against itself and with different y positions */
-
-               if (pItem == this || pItem->y() != y())
-                       continue;
-
-               int start = pItem->x() >= x() ? pItem->x() : x();
-               int end   = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w();
-               if (start < end)
-                       return true;
-       }
-
-       return false;
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::draw() {
-       int _w = w() > 4 ? w() : 4;
-       //gLog("[gPianoItem] draw me (%p) at x=%d\n", (void*)this, x());
-       fl_rectf(x(), y(), _w, h(), (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::record() {
-
-       /* avoid frame overflow */
-
-       int overflow = frame_b - G_Mixer.totalFrames;
-       if (overflow > 0) {
-               frame_b -= overflow;
-               frame_a -= overflow;
-       }
-
-       /* note off */
-       /** FIXME - use constants */
-       event_a |= (0x90 << 24);   // note on
-       event_a |= (note << 16);   // note value
-       event_a |= (0x3F <<  8);   // velocity
-       event_a |= (0x00);
-
-       event_b |= (0x80 << 24);   // note off
-       event_b |= (note << 16);   // note value
-       event_b |= (0x3F <<  8);   // velocity
-       event_b |= (0x00);
-
-       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a);
-       recorder::rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gPianoItem::remove() {
-       recorder::deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0);
-       recorder::deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0);
-
-       /* send a note-off in case we are deleting it in a middle of a key_on
-        * key_off sequence. */
-
-       ((MidiChannel*) pParent->chan)->sendMidi(event_b);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-int gPianoItem::handle(int e) {
-
-       int ret = 0;
-
-       switch (e) {
-
-               case FL_ENTER: {
-                       selected = true;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-
-               case FL_LEAVE: {
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       selected = false;
-                       ret = 1;
-                       redraw();
-                       break;
-               }
-
-               case FL_MOVE: {
-                       onLeftEdge  = false;
-                       onRightEdge = false;
-
-                       if (Fl::event_x() >= x() && Fl::event_x() < x()+4) {
-                               onLeftEdge = true;
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       }
-                       else
-                       if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) {
-                               onRightEdge = true;
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       }
-                       else
-                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-
-                       ret = 1;
-                       break;
-               }
-
-               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();
-                               hide();   // for Windows
-                               Fl::delete_widget(this);
-                               ((gPianoRoll*)parent())->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       changed = true;
-
-                       gPianoRoll *pr = (gPianoRoll*) parent();
-                       int coverX     = pParent->coverX + pr->x(); // relative coverX
-                       int nx, ny, nw;
-
-                       if (onLeftEdge) {
-                               nx = Fl::event_x();
-                               ny = y();
-                               nw = x()-Fl::event_x()+w();
-                               if (nx < pr->x()) {
-                                       nx = pr->x();
-                                       nw = w()+x()-pr->x();
-                               }
-                               else
-                               if (nx > x()+w()-8) {
-                                       nx = x()+w()-8;
-                                       nw = 8;
-                               }
-                               resize(nx, ny, nw, h());
-                       }
-                       else
-                       if (onRightEdge) {
-                               nw = Fl::event_x()-x();
-                               if (Fl::event_x() < x()+8)
-                                       nw = 8;
-                               else
-                               if (Fl::event_x() > coverX)
-                                       nw = coverX-x();
-                               size(nw, h());
-                       }
-                       else {
-                               nx = Fl::event_x() - push_x;
-                               if (nx < pr->x()+1)
-                                       nx = pr->x()+1;
-                               else
-                               if (nx+w() > coverX)
-                                       nx = coverX-w();
-
-                               /* snapping */
-
-                               if (pParent->gridTool->isOn())
-                                       nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1;
-
-                               position(nx, y());
-                       }
-
-                       /* update screen */
-
-                       redraw();
-                       ((gPianoRoll*)parent())->redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-
-                       /* delete & record the action, only if it doesn't overlap with
-                        * another one */
-
-                       if (overlap()) {
-                               resize(old_x, y(), old_w, h());
-                               redraw();
-                       }
-                       else
-                       if (changed) {
-                               remove();
-                               note    = getNote(getRelY());
-                               frame_a = getRelX() * pParent->zoom;
-                               frame_b = (getRelX()+w()) * pParent->zoom;
-                               record();
-                               changed = false;
-                       }
-
-                       ((gPianoRoll*)parent())->redraw();
-
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
diff --git a/src/gui/elems/ge_pianoRoll.h b/src/gui/elems/ge_pianoRoll.h
deleted file mode 100644 (file)
index 509fd32..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_pianoRoll
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef GE_PIANOROLL_H
-#define GE_PIANOROLL_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include "../../core/recorder.h"
-#include "ge_actionWidget.h"
-
-
-class gPianoRollContainer : public Fl_Scroll {
-
-private:
-       class gdActionEditor *pParent;
-       class gPianoRoll     *pianoRoll;
-
-public:
-       gPianoRollContainer(int x, int y, class gdActionEditor *parent);
-       ~gPianoRollContainer();
-       void draw();
-       void updateActions();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gPianoRoll : public gActionWidget {
-
-private:
-
-       /* onItem
-        * is curson on a gPianoItem? */
-
-       bool onItem(int rel_x, int rel_y);
-
-       /* drawSurface*
-        * generate a complex drawing in memory first and copy it to the
-        * screen at a later point in time. Fl_Offscreen surface holds the
-        * necessary data. */
-
-       /* drawSurface1
-        * draw first tile of note values. */
-
-       void drawSurface1();
-
-       /* drawSurface2
-        * draw the rest of the piano roll. */
-
-       void drawSurface2();
-
-       int  push_y;
-       Fl_Offscreen surface1;  // notes, no repeat
-       Fl_Offscreen surface2;  // lines, x-repeat
-
-
-public:
-       gPianoRoll(int x, int y, int w, class gdActionEditor *pParent);
-
-       void draw();
-       int  handle(int e);
-       void updateActions();
-
-       enum { MAX_NOTES = 127, CELL_H = 15 };
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gPianoItem : public Fl_Box {
-
-private:
-
-       /* getRelX/Y
-        * return x/y point of this item, relative to piano roll (and not to
-        * entire screen) */
-
-       inline int getRelY() { return y() - parent()->y() - 3; };
-       inline int getRelX() { return x() - parent()->x(); };
-
-       /* getNote
-        * from a relative_y return the real MIDI note, range 0-127. 15 is
-        * the hardcoded value for note height in pixels */
-
-       inline int getNote(int rel_y) {
-               return gPianoRoll::MAX_NOTES - (rel_y / gPianoRoll::CELL_H);
-       };
-
-       /* getY
-        * from a note, return the y position on piano roll */
-
-       inline int getY(int note) {
-               return (gPianoRoll::MAX_NOTES * gPianoRoll::CELL_H) - (note * gPianoRoll::CELL_H);
-       };
-
-       /* overlap
-        * check if this item don't overlap with another one. */
-
-       bool overlap();
-
-       recorder::action *a;
-       recorder::action *b;
-       class gdActionEditor *pParent;
-
-       bool selected;
-       int  push_x;
-
-       /* MIDI note, start frame, end frame - Used only if it's a newly added
-        * action */ /** FIXME - is it true? */
-
-       int  note;
-       int  frame_a;
-       int  frame_b;
-
-       /* 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 */
-
-       bool changed;
-
-       /* 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 */
-
-       int old_x, old_w;
-
-public:
-
-       /* pianoItem ctor
-        * if action *a == NULL, record a new action */
-
-       gPianoItem(int x, int y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, class gdActionEditor *pParent);
-
-       void draw();
-       int  handle(int e);
-       void record();
-       void remove();
-
-       inline int getFrame_a() { return frame_a; }
-       inline int getFrame_b() { return frame_b; }
-       inline int getNote()    { return note;    }
-
-};
-
-#endif
diff --git a/src/gui/elems/ge_sampleChannel.cpp b/src/gui/elems/ge_sampleChannel.cpp
deleted file mode 100644 (file)
index 3838a9e..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_sampleChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../../core/pluginHost.h"
-#include "../../core/mixer.h"
-#include "../../core/conf.h"
-#include "../../core/patch_DEPR_.h"
-#include "../../core/graphics.h"
-#include "../../core/channel.h"
-#include "../../core/wave.h"
-#include "../../core/sampleChannel.h"
-#include "../../core/midiChannel.h"
-#include "../../glue/glue.h"
-#include "../../glue/channel.h"
-#include "../../glue/storage.h"
-#include "../../utils/gui_utils.h"
-#include "../dialogs/gd_mainWindow.h"
-#include "../dialogs/gd_keyGrabber.h"
-#include "../dialogs/gd_midiInput.h"
-#include "../dialogs/gd_editor.h"
-#include "../dialogs/gd_actionEditor.h"
-#include "../dialogs/gd_warnings.h"
-#include "../dialogs/gd_browser.h"
-#include "../dialogs/gd_midiOutput.h"
-#include "../dialogs/gd_pluginList.h"
-#include "../dialogs/gd_pluginChooser.h"
-#include "ge_keyboard.h"
-#include "ge_sampleChannel.h"
-#include "ge_status.h"
-#include "ge_modeBox.h"
-
-
-extern Mixer                G_Mixer;
-extern Conf                 G_Conf;
-extern Patch_DEPR_   G_Patch_DEPR_;
-extern gdMainWindow *mainWin;
-
-
-gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel *ch)
-       : gChannel(X, Y, W, H, CHANNEL_SAMPLE), ch(ch)
-{
-       begin();
-
-#if defined(WITH_VST)
-  int delta = 168; // (7 widgets * 20) + (7 paddings * 4)
-#else
-       int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
-#endif
-
-       button       = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
-       status       = new gStatus(button->x()+button->w()+4, y(), 20, 20, ch);
-       mainButton   = new gSampleChannelButton(status->x()+status->w()+4, y(), w() - delta, 20, "-- no sample --");
-       modeBox      = new gModeBox(mainButton->x()+mainButton->w()+4, y(), 20, 20, ch);
-       mute         = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo         = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
-       readActions  = NULL; // no 'R' button
-
-#if defined(WITH_VST)
-       fx           = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol          = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
-#else
-       vol          = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
-#endif
-
-       end();
-
-  resizable(mainButton);
-
-       update();
-
-       button->callback(cb_button, (void*)this);
-       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
-
-#ifdef WITH_VST
-       fx->callback(cb_openFxWindow, (void*)this);
-#endif
-
-       mute->type(FL_TOGGLE_BUTTON);
-       mute->callback(cb_mute, (void*)this);
-
-       solo->type(FL_TOGGLE_BUTTON);
-       solo->callback(cb_solo, (void*)this);
-
-       mainButton->callback(cb_openMenu, (void*)this);
-
-       vol->callback(cb_changeVol, (void*)this);
-
-       ch->guiChannel = this;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::cb_button      (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_button(); }
-void gSampleChannel::cb_mute        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_mute(); }
-void gSampleChannel::cb_solo        (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_solo(); }
-void gSampleChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openMenu(); }
-void gSampleChannel::cb_changeVol   (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_changeVol(); }
-void gSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_readActions(); }
-#ifdef WITH_VST
-void gSampleChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openFxWindow(); }
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_mute()
-{
-       glue_setMute(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_solo()
-{
-       solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_changeVol()
-{
-       glue_setChanVol(ch, vol->value());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-void gSampleChannel::__cb_openFxWindow()
-{
-       gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST);
-}
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-
-void gSampleChannel::__cb_button()
-{
-       if (button->value())    // pushed
-               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
-       else                    // released
-               glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_openMenu()
-{
-       /* if you're recording (actions or input) no menu is allowed; you can't
-        * do anything, especially deallocate the channel */
-
-       if (G_Mixer.chanInput == ch || recorder::active)
-               return;
-
-       /* the following is a trash workaround for a FLTK menu. We need a gMenu
-        * widget asap */
-
-       Fl_Menu_Item rclick_menu[] = {
-               {"Load new sample..."},                     // 0
-               {"Export sample to file..."},               // 1
-               {"Setup keyboard input..."},                // 2
-               {"Setup MIDI input..."},                    // 3
-               {"Setup MIDI output..."},                   // 4
-               {"Edit sample..."},                         // 5
-               {"Edit actions..."},                        // 6
-               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 7
-                       {"All"},                                  // 8
-                       {"Mute"},                                 // 9
-                       {"Volume"},                               // 10
-                       {"Start/Stop"},                           // 11
-                       {0},                                      // 12
-                       {"Clone channel"},                        // 13
-               {"Free channel"},                           // 14
-               {"Delete channel"},                         // 15
-               {0}
-       };
-
-       if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) {
-               rclick_menu[1].deactivate();
-               rclick_menu[5].deactivate();
-               rclick_menu[14].deactivate();
-       }
-
-       /* no 'clear actions' if there are no actions */
-
-       if (!ch->hasActions)
-               rclick_menu[7].deactivate();
-
-       /* no 'clear start/stop actions' for those channels in loop mode:
-        * they cannot have start/stop actions. */
-
-       if (ch->mode & LOOP_ANY)
-               rclick_menu[11].deactivate();
-
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
-       b->box(G_BOX);
-       b->textsize(GUI_FONT_SIZE_BASE);
-       b->textcolor(COLOR_TEXT_0);
-       b->color(COLOR_BG_0);
-
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-       if (!m) return;
-
-       if (strcmp(m->label(), "Load new sample...") == 0) {
-               openBrowser(BROWSER_LOAD_SAMPLE);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
-               new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0);
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit sample...") == 0) {
-               gu_openSubWindow(mainWin, new gdEditor(ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor
-               return;
-       }
-
-       if (strcmp(m->label(), "Export sample to file...") == 0) {
-               openBrowser(BROWSER_SAVE_SAMPLE);
-               return;
-       }
-
-       if (strcmp(m->label(), "Delete channel") == 0) {
-               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
-                       return;
-               glue_deleteChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Free channel") == 0) {
-               if (ch->status == STATUS_PLAY) {
-                       if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
-                               return;
-               }
-               else if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
-                       return;
-
-               glue_freeChannel(ch);
-
-               /* delete any related subwindow */
-
-               /** FIXME - use gu_closeAllSubwindows() */
-
-               mainWin->delSubWindow(WID_FILE_BROWSER);
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
-               mainWin->delSubWindow(WID_SAMPLE_EDITOR);
-               mainWin->delSubWindow(WID_FX_LIST);
-
-               return;
-       }
-
-       if (strcmp(m->label(), "Clone channel") == 0) {
-               glue_cloneChannel(ch);
-               return;
-       }
-
-       if (strcmp(m->label(), "Mute") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF);
-               if (!ch->hasActions)
-                       delActionButton();
-
-               /* TODO - set mute=false */
-
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Start/Stop") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN);
-               if (!ch->hasActions)
-                       delActionButton();
-               gu_refreshActionEditor();  // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Volume") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
-                       return;
-               recorder::clearAction(ch->index, ACTION_VOLUME);
-               if (!ch->hasActions)
-                       delActionButton();
-               gu_refreshActionEditor();  // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "All") == 0) {
-               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-                       return;
-               recorder::clearChan(ch->index);
-               delActionButton();
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-               return;
-       }
-
-       if (strcmp(m->label(), "Edit actions...") == 0) {
-               gu_openSubWindow(mainWin, new gdActionEditor(ch),       WID_ACTION_EDITOR);
-               return;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::__cb_readActions()
-{
-       ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::openBrowser(int type)
-{
-       gWindow *childWin = NULL;
-       switch (type) {
-               case BROWSER_LOAD_SAMPLE:
-                       childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY,
-                                       G_Conf.browserW, G_Conf.browserH, "Browse sample",
-                                       G_Conf.samplePath.c_str(), glue_loadSample, ch);
-                       break;
-               case BROWSER_SAVE_SAMPLE:
-                       childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY,
-                                       G_Conf.browserW, G_Conf.browserH, "Save sample", \
-                                       G_Conf.samplePath.c_str(), "", glue_saveSample, ch);
-                       break;
-       }
-       if (childWin)
-               gu_openSubWindow(mainWin, childWin,     WID_FILE_BROWSER);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::refresh()
-{
-  if (!mainButton->visible()) // mainButton invisible? status too (see below)
-    return;
-
-       setColorsByStatus(ch->status, ch->recStatus);
-
-       if (ch->wave != NULL) {
-               if (G_Mixer.chanInput == ch)
-                       mainButton->setInputRecordMode();
-               if (recorder::active) {
-                       if (recorder::canRec(ch))
-                               mainButton->setActionRecordMode();
-               }
-               status->redraw(); // status invisible? sampleButton too (see below)
-       }
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::reset()
-{
-       delActionButton(true); // force==true, don't check, just remove it
-       mainButton->setDefaultMode("-- no sample --");
-       mainButton->redraw();
-       status->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::update()
-{
-       /* update sample button's label */
-
-       switch (ch->status) {
-               case STATUS_EMPTY:
-                       mainButton->label("-- no sample --");
-                       break;
-               case STATUS_MISSING:
-               case STATUS_WRONG:
-                       mainButton->label("* file not found! *");
-                       break;
-               default:
-                       mainButton->label(ch->wave->name.c_str());
-                       break;
-       }
-
-       /* update channels. If you load a patch with recorded actions, the 'R'
-        * button must be shown. Moreover if the actions are active, the 'R'
-        * button must be activated accordingly. */
-
-       if (ch->hasActions)
-               addActionButton();
-       else
-               delActionButton();
-
-       /* updates modebox */
-
-       modeBox->value(ch->mode);
-       modeBox->redraw();
-
-       /* update volumes+mute+solo */
-
-       vol->value(ch->volume);
-       mute->value(ch->mute);
-       solo->value(ch->solo);
-
-       mainButton->setKey(ch->key);
-
-#ifdef WITH_VST
-       fx->full = ch->plugins.size() > 0;
-       fx->redraw();
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gSampleChannel::keyPress(int e)
-{
-       return handleKey(e, ch->key);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::addActionButton()
-{
-       /* quit if 'R' exists yet. */
-
-       if (readActions != NULL)
-               return;
-
-       mainButton->size(mainButton->w()-24, mainButton->h());
-
-       redraw();
-
-       readActions = new gClick(mainButton->x() + mainButton->w() + 4,
-                           mainButton->y(), 20, 20, "", readActionOff_xpm,
-                           readActionOn_xpm);
-       readActions->type(FL_TOGGLE_BUTTON);
-       readActions->value(ch->readActions);
-       readActions->callback(cb_readActions, (void*)this);
-       add(readActions);
-
-       /* hard redraw: there's no other way to avoid glitches when moving
-        * the 'R' button */
-
-       mainWin->keyboard->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::delActionButton(bool force)
-{
-       if (readActions == NULL)
-               return;
-
-       /* TODO - readActions check is useless here */
-
-       if (!force && (readActions == NULL || ch->hasActions))
-               return;
-
-       remove(readActions);            // delete from Keyboard group (FLTK)
-       delete readActions;     // delete (C++)
-       readActions = NULL;
-
-       mainButton->size(mainButton->w()+24, mainButton->h());
-       mainButton->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSampleChannel::resize(int X, int Y, int W, int H)
-{
-  gChannel::resize(X, Y, W, H);
-
-       if (w() < BREAK_FX) {
-#ifdef WITH_VST
-               fx->hide();
-#endif
-               mainButton->size(w() - BREAK_DELTA, mainButton->h());
-               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-
-               /* The followings are useless on manual resizing, but useful when a channel
-                * is added from a patch with a small width. */
-
-         modeBox->hide();
-               if (readActions)
-      readActions->hide();
-       }
-       else
-       if (w() < BREAK_MODE_BOX) {
-#ifdef WITH_VST
-               fx->show();
-#endif
-               mainButton->size(w() - (BREAK_DELTA + BREAK_UNIT), mainButton->h());
-               mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               solo->resize(mute->x()+mute->w()+4, y(), 20, 20);
-    modeBox->hide();
-       }
-       else
-       if (w() < BREAK_READ_ACTIONS) {
-    modeBox->show();
-    mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h());
-    modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-               if (readActions)
-      readActions->hide();
-       }
-       else {
-               if (readActions) {
-      mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 3)), mainButton->h());
-      readActions->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20);
-      readActions->show();
-               }
-       }
-
-       gChannel::init_sizes();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gSampleChannelButton::gSampleChannelButton(int x, int y, int w, int h, const char *l)
-       : gChannelButton(x, y, w, h, l) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gSampleChannelButton::handle(int e)
-{
-       int ret = gClick::handle(e);
-       switch (e) {
-               case FL_DND_ENTER:
-               case FL_DND_DRAG:
-               case FL_DND_RELEASE: {
-                       ret = 1;
-                       break;
-               }
-               case FL_PASTE: {
-      gSampleChannel *gch = (gSampleChannel*) parent();   // parent is gSampleChannel
-      SampleChannel  *ch  = gch->ch;
-      int result = glue_loadChannel(ch, gTrim(gStripFileUrl(Fl::event_text())).c_str());
-                       if (result != SAMPLE_LOADED_OK)
-                               mainWin->keyboard->printChannelMessage(result);
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
diff --git a/src/gui/elems/ge_sampleChannel.h b/src/gui/elems/ge_sampleChannel.h
deleted file mode 100644 (file)
index db5beb2..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ge_sampleChannel
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_SAMPLE_CHANNEL_H
-#define GE_SAMPLE_CHANNEL_H
-
-
-#include <FL/Fl_Scroll.H>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Menu_Button.H>
-#include "ge_channel.h"
-#include "ge_channelButton.h"
-#include "ge_mixed.h"
-
-
-class gSampleChannel : public gChannel
-{
-private:
-
-       static void cb_button        (Fl_Widget *v, void *p);
-       static void cb_mute          (Fl_Widget *v, void *p);
-       static void cb_solo          (Fl_Widget *v, void *p);
-       static void cb_openMenu      (Fl_Widget *v, void *p);
-       static void cb_changeVol     (Fl_Widget *v, void *p);
-       static void cb_readActions   (Fl_Widget *v, void *p);
-#ifdef WITH_VST
-       static void cb_openFxWindow  (Fl_Widget *v, void *p);
-#endif
-
-       inline void __cb_mute        ();
-       inline void __cb_solo        ();
-       inline void __cb_changeVol   ();
-       inline void __cb_button      ();
-       inline void __cb_openMenu    ();
-       inline void __cb_readActions ();
-#ifdef WITH_VST
-       inline void __cb_openFxWindow();
-#endif
-
-       void openBrowser(int type);
-
-public:
-
-       gSampleChannel(int x, int y, int w, int h, class SampleChannel *ch);
-
-       void reset   ();
-       void update  ();
-       void refresh ();
-       int  keyPress(int event);
-       void resize  (int x, int y, int w, int h);
-
-       /* add/delActionButton
-        * add or remove 'R' button when actions are available. 'Status' is
-        * the initial status of the button: on or off.
-        * If force==true remove the button with no further checks. */
-
-       void addActionButton();
-       void delActionButton(bool force=false);
-       
-       class gModeBox *modeBox;
-       class gClick     *readActions;
-
-       class SampleChannel *ch;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gSampleChannelButton : public gChannelButton
-{
-public:
-       gSampleChannelButton(int x, int y, int w, int h, const char *l=0);
-       int handle(int e);
-};
-
-
-#endif
index 8acaf0f4dbf0f5ecbbd47b47cc81e3a51fd0187d..80cbac7bc3d3fe6083418513101fbe61371828d2 100644 (file)
 
 
 #include "../../core/mixer.h"
+#include "../../core/const.h"
 #include "ge_status.h"
 
 
-extern Mixer G_Mixer;
+extern Mixer    G_Mixer;
+extern Recorder G_Recorder;
 
 
 gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L)
@@ -59,10 +61,10 @@ void gStatus::draw()
       fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0);     // status empty
 
 
-    if (G_Mixer.chanInput == ch)
+    if (G_Mixer.recording && ch->armed)
       fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3);     // take in progress
     else
-    if (recorder::active && recorder::canRec(ch))
+    if (G_Recorder.active && G_Recorder.canRec(ch))
       fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4);     // action record
 
     /* equation for the progress bar:
index 49f97351c105b45080cf37143ecfca2b4942af30..7e7b1979f6998e8e470cca1c248a454312c8450d 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "../../core/graphics.h"
 #include "../../core/mixer.h"
+#include "../../core/const.h"
 #include "../elems/ge_mixed.h"
 #include "../elems/ge_waveform.h"
 #include "ge_waveTools.h"
@@ -54,7 +55,7 @@ gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char
 /* ------------------------------------------------------------------ */
 
 
-void gWaveTools::updateWaveform() 
+void gWaveTools::updateWaveform()
 {
        waveform->alloc(w());
        waveform->redraw();
@@ -64,7 +65,7 @@ void gWaveTools::updateWaveform()
 /* ------------------------------------------------------------------ */
 
 
-void gWaveTools::resize(int x, int y, int w, int h) 
+void gWaveTools::resize(int x, int y, int w, int h)
 {
        if (this->w() == w || (this->w() != w && this->h() != h)) {   // vertical or both resize
                Fl_Widget::resize(x, y, w, h);
@@ -87,7 +88,7 @@ void gWaveTools::resize(int x, int y, int w, int h)
 /* ------------------------------------------------------------------ */
 
 
-int gWaveTools::handle(int e) 
+int gWaveTools::handle(int e)
 {
        int ret = Fl_Group::handle(e);
        switch (e) {
@@ -100,4 +101,3 @@ int gWaveTools::handle(int e)
        }
        return ret;
 }
-
index 5d8a48f527cf9b20b8cb2b86e23593c66eec405e..dd893ce200fbabd11b3cdf390177e1702f7811d8 100644 (file)
 #include <samplerate.h>
 #include "../../core/wave.h"
 #include "../../core/conf.h"
+#include "../../core/const.h"
 #include "../../core/mixer.h"
 #include "../../core/waveFx.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
-#include "../../glue/glue.h"
+#include "../../glue/channel.h"
 #include "../dialogs/gd_editor.h"
 #include "ge_waveTools.h"
 #include "ge_mixed.h"
@@ -250,7 +251,7 @@ void gWaveform::draw()
 
     for (unsigned k=0; k<grid.points.size(); k++) {
       if (grid.points.at(k) == i) {
-        //gLog("draw grid line at %d\n", i);
+        //gu_log("draw grid line at %d\n", i);
         fl_color(fl_rgb_color(54, 54, 54));
         fl_line_style(FL_DASH, 0, NULL);
         fl_line(i+x(), y(), i+x(), y()+h());
index 143464a7e9150de9040611f3f6fd03aef58b0484..77a528f025122f1d4d3f868a65b5e9cc4b21f7ac 100644 (file)
@@ -37,7 +37,7 @@
 #include <FL/Fl_Widget.H>
 #include <FL/fl_draw.H>
 #include <math.h>
-#include "../../utils/utils.h"
+#include "../../utils/fs.h"
 
 
 using std::vector;
index 30c26cbe57ffd686868e0f2843114d561cb91bd3..e14fcb8c3bf3f88f23f7e1561812f90d11521030 100644 (file)
@@ -75,7 +75,7 @@ void gWindow::addSubWindow(gWindow *w) {
        /** TODO - useless: delete ---------------------------------------- */
        for (unsigned i=0; i<subWindows.size(); i++)
                if (w->getId() == subWindows.at(i)->getId()) {
-                       //gLog("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId());
+                       //gu_log("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId());
                        delete w;
                        return;
                }
@@ -138,10 +138,10 @@ void gWindow::setId(int id) {
 
 
 void gWindow::debug() {
-       gLog("---- window stack (id=%d): ----\n", getId());
+       gu_log("---- window stack (id=%d): ----\n", getId());
        for (unsigned i=0; i<subWindows.size(); i++)
-               gLog("[gWindow] %p (id=%d)\n", (void*)subWindows.at(i), subWindows.at(i)->getId());
-       gLog("----\n");
+               gu_log("[gWindow] %p (id=%d)\n", (void*)subWindows.at(i), subWindows.at(i)->getId());
+       gu_log("----\n");
 }
 
 
index 4991b0f476fd4cc22a826d351edba27eccb15c17..e986d8d489026443c7b86ac523309dfe4cb174c5 100644 (file)
@@ -34,7 +34,7 @@
 
 #include <vector>
 #include <FL/Fl_Double_Window.H>
-#include "../../utils/utils.h"
+#include "../../utils/fs.h"
 
 
 using std::vector;
diff --git a/src/gui/elems/midiChannel.cpp b/src/gui/elems/midiChannel.cpp
new file mode 100644 (file)
index 0000000..bfdbea5
--- /dev/null
@@ -0,0 +1,291 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch_DEPR_.h"
+#include "../../core/graphics.h"
+#include "../../core/channel.h"
+#include "../../core/midiChannel.h"
+#include "../../glue/channel.h"
+#include "../../glue/main.h"
+#include "../../glue/io.h"
+#include "../../utils/gui.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiInput.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_warnings.h"
+#include "../dialogs/gd_browser.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiOutput.h"
+#include "../dialogs/gd_pluginList.h"
+#include "midiChannel.h"
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Recorder                         G_Recorder;
+extern Patch_DEPR_   G_Patch_DEPR_;
+extern gdMainWindow *G_MainWin;
+
+
+geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch)
+       : geChannel(X, Y, W, H, CHANNEL_MIDI, ch)
+{
+       begin();
+
+#if defined(WITH_VST)
+  int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
+#else
+       int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
+#endif
+
+       button     = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
+       arm        = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
+       mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --");
+       mute       = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
+       solo       = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+#if defined(WITH_VST)
+       fx         = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
+       vol        = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
+#else
+       vol        = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
+#endif
+
+       end();
+
+  resizable(mainButton);
+
+       update();
+
+       button->callback(cb_button, (void*)this);
+       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
+
+       arm->type(FL_TOGGLE_BUTTON);
+       arm->callback(cb_arm, (void*)this);
+
+#ifdef WITH_VST
+       fx->callback(cb_openFxWindow, (void*)this);
+#endif
+
+       mute->type(FL_TOGGLE_BUTTON);
+       mute->callback(cb_mute, (void*)this);
+
+       solo->type(FL_TOGGLE_BUTTON);
+       solo->callback(cb_solo, (void*)this);
+
+       mainButton->callback(cb_openMenu, (void*)this);
+
+       vol->callback(cb_changeVol, (void*)this);
+
+       ch->guiChannel = this;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::cb_button      (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_button(); }
+void geMidiChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_openMenu(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::__cb_button()
+{
+       if (button->value())
+               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::__cb_openMenu()
+{
+       Fl_Menu_Item rclick_menu[] = {
+               {"Edit actions..."},                        // 0
+               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 1
+                       {"All"},                                  // 2
+                       {0},                                      // 3
+               {"Setup keyboard input..."},                // 5
+               {"Setup MIDI input..."},                    // 6
+               {"Setup MIDI output..."},                   // 7
+               {"Clone channel"},                          // 8
+               {"Delete channel"},                         // 9
+               {0}
+       };
+
+       /* no 'clear actions' if there are no actions */
+
+       if (!ch->hasActions)
+               rclick_menu[1].deactivate();
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(GUI_FONT_SIZE_BASE);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+       if (strcmp(m->label(), "Delete channel") == 0) {
+               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+                       return;
+               glue_deleteChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Clone channel") == 0) {
+               glue_cloneChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdKeyGrabber(ch),       0);
+               //new gdKeyGrabber(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "All") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+                       return;
+               G_Recorder.clearChan(ch->index);
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit actions...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdActionEditor(ch),     WID_ACTION_EDITOR);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               //gu_openSubWindow(G_MainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0);
+               gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh((MidiChannel*) ch), 0);
+               return;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::refresh()
+{
+       setColorsByStatus(ch->status, ch->recStatus);
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::reset()
+{
+       mainButton->setDefaultMode("-- MIDI --");
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::update()
+{
+       if (((MidiChannel*) ch)->midiOut) {
+               char tmp[32];
+               sprintf(tmp, "-- MIDI (channel %d) --", ((MidiChannel*) ch)->midiOutChan+1);
+               mainButton->copy_label(tmp);
+       }
+       else
+               mainButton->label("-- MIDI --");
+
+       vol->value(ch->volume);
+       mute->value(ch->mute);
+       solo->value(ch->solo);
+
+       mainButton->setKey(ch->key);
+
+#ifdef WITH_VST
+       fx->full = ch->plugins.size() > 0;
+       fx->redraw();
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMidiChannel::resize(int X, int Y, int W, int H)
+{
+  geChannel::resize(X, Y, W, H);
+
+       arm->hide();
+#ifdef WITH_VST
+       fx->hide();
+#endif
+
+       if (w() > BREAK_ARM)
+               arm->show();
+#ifdef WITH_VST
+       if (w() > BREAK_FX)
+               fx->show();
+#endif
+
+       packWidgets();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char *l)
+       : geChannelButton(x, y, w, h, l) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geMidiChannelButton::handle(int e)
+{
+       // MIDI drag-n-drop does nothing so far.
+       return gClick::handle(e);
+}
diff --git a/src/gui/elems/midiChannel.h b/src/gui/elems/midiChannel.h
new file mode 100644 (file)
index 0000000..cd06ddc
--- /dev/null
@@ -0,0 +1,72 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_MIDI_CHANNEL_H
+#define GE_MIDI_CHANNEL_H
+
+
+#include "channel.h"
+#include "channelButton.h"
+
+
+class geMidiChannel : public geChannel
+{
+private:
+
+       static void cb_button        (Fl_Widget *v, void *p);
+       static void cb_openMenu      (Fl_Widget *v, void *p);
+
+       inline void __cb_button      ();
+       inline void __cb_openMenu    ();
+       inline void __cb_readActions ();
+
+public:
+
+       geMidiChannel(int x, int y, int w, int h,  class MidiChannel *ch);
+
+       void reset   ();
+       void update  ();
+       void refresh ();
+       int  keyPress(int event);  // TODO - move to base class
+       void resize  (int x, int y, int w, int h);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class geMidiChannelButton : public geChannelButton
+{
+public:
+       geMidiChannelButton(int x, int y, int w, int h, const char *l=0);
+       int handle(int e);
+};
+
+
+#endif
diff --git a/src/gui/elems/muteEditor.cpp b/src/gui/elems/muteEditor.cpp
new file mode 100644 (file)
index 0000000..e2861b2
--- /dev/null
@@ -0,0 +1,410 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/recorder.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../../glue/main.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "ge_keyboard.h"
+#include "muteEditor.h"
+
+
+extern gdMainWindow *G_MainWin;
+extern Mixer         G_Mixer;
+extern Recorder      G_Recorder;
+
+
+geMuteEditor::geMuteEditor(int x, int y, gdActionEditor *pParent)
+ : geBaseActionEditor(x, y, 200, 80, pParent),
+   draggedPoint      (-1),
+   selectedPoint     (-1)
+{
+       size(pParent->totalWidth, h());
+       extractPoints();
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geMuteEditor::draw()
+{
+       baseDraw();
+
+       /* print label */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 12);
+       fl_draw("mute", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+
+       /* draw "on" and "off" labels. Must stay in background */
+
+       fl_color(COLOR_BG_1);
+       fl_font(FL_HELVETICA, 9);
+       fl_draw("on",  x()+4, y(),        w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+       fl_draw("off", x()+4, y()+h()-14, w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+
+       /* draw on-off points. On = higher rect, off = lower rect. It always
+        * starts with a note_off */
+
+       fl_color(COLOR_BG_2);
+
+       int pxOld = x()+1;
+       int pxNew = 0;
+       int py    = y()+h()-5;
+       int pyDot = py-6;
+
+       for (unsigned i=0; i<points.size(); i++) {
+
+               /* next px */
+
+               pxNew = points.at(i).x+x();
+
+               /* draw line from pxOld to pxNew.
+                * i % 2 == 0: first point, mute_on
+                * i % 2 != 0: second point, mute_off */
+
+               fl_line(pxOld, py, pxNew, py);
+               pxOld = pxNew;
+
+               py = i % 2 == 0 ? y()+4 : y()+h()-5;
+
+               /* draw dots (handles) */
+
+               fl_line(pxNew, y()+h()-5, pxNew, y()+4);
+
+               if (selectedPoint == (int) i) {
+                       fl_color(COLOR_BD_1);
+                       fl_rectf(pxNew-3, pyDot, 7, 7);
+                       fl_color(COLOR_BG_2);
+               }
+               else
+                       fl_rectf(pxNew-3, pyDot, 7, 7);
+       }
+
+       /* last section */
+
+       py = y()+h()-5;
+       fl_line(pxNew+3, py, pParent->coverX+x()-1, py);
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geMuteEditor::extractPoints()
+{
+       points.clear();
+
+       /* actions are already sorted by G_Recorder.sortActions() */
+
+       for (unsigned i=0; i<G_Recorder.frames.size(); i++) {
+               for (unsigned j=0; j<G_Recorder.global.at(i).size(); j++) {
+                       if (G_Recorder.global.at(i).at(j)->chan == pParent->chan->index) {
+                               if (G_Recorder.global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) {
+                                       point p;
+                                       p.frame = G_Recorder.frames.at(i);
+                                       p.type  = G_Recorder.global.at(i).at(j)->type;
+                                       p.x     = p.frame / pParent->zoom;
+                                       points.push_back(p);
+                                       //gu_log("[geMuteEditor::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+void geMuteEditor::updateActions() {
+       for (unsigned i=0; i<points.size(); i++)
+               points.at(i).x = points.at(i).frame / pParent->zoom;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int geMuteEditor::handle(int e) {
+
+       int ret = 0;
+       int mouseX = Fl::event_x()-x();
+
+       switch (e) {
+
+               case FL_ENTER: {
+                       ret = 1;
+                       break;
+               }
+
+               case FL_MOVE: {
+                       selectedPoint = getSelectedPoint();
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+                       redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_PUSH: {
+
+                       /* left click on point: drag
+                        * right click on point: delete
+                        * left click on void: add */
+
+                       if (Fl::event_button1())  {
+
+                               if (selectedPoint != -1) {
+                                       draggedPoint   = selectedPoint;
+                                       previousXPoint = points.at(selectedPoint).x;
+                               }
+                               else {
+
+                                       /* click on the grey area leads to nowhere */
+
+                                       if (mouseX > pParent->coverX) {
+                                               ret = 1;
+                                               break;
+                                       }
+
+                                       /* click in the middle of a long mute_on (between two points): new actions
+                                        * must be added in reverse: first mute_off then mute_on. Let's find the
+                                        * next point from here. */
+
+                                       unsigned nextPoint = points.size();
+                                       for (unsigned i=0; i<points.size(); i++) {
+                                               if (mouseX < points.at(i).x) {
+                                                       nextPoint = i;
+                                                       break;
+                                               }
+                                       }
+
+                                       /* next point odd = mute_on [click here] mute_off
+                                        * next point even = mute_off [click here] mute_on */
+
+                                       int frame_a = mouseX * pParent->zoom;
+                                       int frame_b = frame_a+2048;
+
+                                       if (pParent->gridTool->isOn()) {
+                                               frame_a = pParent->gridTool->getSnapFrame(mouseX);
+                                               frame_b = pParent->gridTool->getSnapFrame(mouseX + pParent->gridTool->getCellSize());
+
+                                               /* with snap=on a point can fall onto another */
+
+                                               if (pointCollides(frame_a) || pointCollides(frame_b)) {
+                                                       ret = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       /* ensure frame parity */
+
+                                       if (frame_a % 2 != 0) frame_a++;
+                                       if (frame_b % 2 != 0) frame_b++;
+
+                                       /* avoid overflow: frame_b must be within the sequencer range. In that
+                                        * case shift the ON-OFF block */
+
+                                       if (frame_b >= G_Mixer.totalFrames) {
+                                               frame_b = G_Mixer.totalFrames;
+                                               frame_a = frame_b-2048;
+                                       }
+
+                                       if (nextPoint % 2 != 0) {
+                                               G_Recorder.rec(pParent->chan->index, ACTION_MUTEOFF, frame_a);
+                                               G_Recorder.rec(pParent->chan->index, ACTION_MUTEON,  frame_b);
+                                       }
+                                       else {
+                                               G_Recorder.rec(pParent->chan->index, ACTION_MUTEON,  frame_a);
+                                               G_Recorder.rec(pParent->chan->index, ACTION_MUTEOFF, frame_b);
+                                       }
+                                       G_Recorder.sortActions();
+
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       extractPoints();
+                                       redraw();
+                               }
+                       }
+                       else {
+
+                               /* delete points pair */
+
+                               if (selectedPoint != -1) {
+
+                                       unsigned a;
+                                       unsigned b;
+
+                                       if (points.at(selectedPoint).type == ACTION_MUTEOFF) {
+                                               a = selectedPoint-1;
+                                               b = selectedPoint;
+                                       }
+                                       else {
+                                               a = selectedPoint;
+                                               b = selectedPoint+1;
+                                       }
+
+                                       //gu_log("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n",
+                                       //              a, b, points.at(a).frame, points.at(b).frame);
+
+                                       G_Recorder.deleteAction(pParent->chan->index, points.at(a).frame,       points.at(a).type, false); // false = don't check vals
+                                       G_Recorder.deleteAction(pParent->chan->index,   points.at(b).frame,     points.at(b).type, false); // false = don't check vals
+                                       G_Recorder.sortActions();
+
+                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow
+                                       extractPoints();
+                                       redraw();
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+
+                       if (draggedPoint != -1) {
+
+                               if (points.at(draggedPoint).x == previousXPoint) {
+                                       //gu_log("nothing to do\n");
+                               }
+                               else {
+
+                                       int newFrame = points.at(draggedPoint).x * pParent->zoom;
+
+                                       G_Recorder.deleteAction(
+                                                       pParent->chan->index,
+                                                       points.at(draggedPoint).frame,
+                                                       points.at(draggedPoint).type,
+                                                       false);  // don't check values
+
+                                       G_Recorder.rec(
+                                                       pParent->chan->index,
+                                                       points.at(draggedPoint).type,
+                                                       newFrame);
+
+                                       G_Recorder.sortActions();
+
+                                       points.at(draggedPoint).frame = newFrame;
+                               }
+                       }
+                       draggedPoint  = -1;
+                       selectedPoint = -1;
+
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       if (draggedPoint != -1) {
+
+                               /* constrain the point between two ends (leftBorder-point,
+                                * point-point, point-rightBorder) */
+
+                               int prevPoint;
+                               int nextPoint;
+
+                               if (draggedPoint == 0) {
+                                       prevPoint = 0;
+                                       nextPoint = points.at(draggedPoint+1).x - 1;
+                                       if (pParent->gridTool->isOn())
+                                               nextPoint -= pParent->gridTool->getCellSize();
+                               }
+                               else
+                               if ((unsigned) draggedPoint == points.size()-1) {
+                                       prevPoint = points.at(draggedPoint-1).x + 1;
+                                       nextPoint = pParent->coverX-x();
+                                       if (pParent->gridTool->isOn())
+                                               prevPoint += pParent->gridTool->getCellSize();
+                               }
+                               else {
+                                       prevPoint = points.at(draggedPoint-1).x + 1;
+                                       nextPoint = points.at(draggedPoint+1).x - 1;
+                                       if (pParent->gridTool->isOn()) {
+                                               prevPoint += pParent->gridTool->getCellSize();
+                                               nextPoint -= pParent->gridTool->getCellSize();
+                                       }
+                               }
+
+                               if (mouseX <= prevPoint)
+                                       points.at(draggedPoint).x = prevPoint;
+                               else
+                               if (mouseX >= nextPoint)
+                                       points.at(draggedPoint).x = nextPoint;
+                               else
+                               if (pParent->gridTool->isOn())
+                                       points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mouseX)-1;
+                               else
+                                       points.at(draggedPoint).x = mouseX;
+
+                               redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+       }
+
+
+       return ret;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+bool geMuteEditor::pointCollides(int frame) {
+       for (unsigned i=0; i<points.size(); i++)
+               if (frame == points.at(i).frame)
+                       return true;
+       return false;
+}
+
+
+/* ------------------------------------------------------------------ */
+
+
+int geMuteEditor::getSelectedPoint() {
+
+       /* point is a 7x7 dot */
+
+       for (unsigned i=0; i<points.size(); i++) {
+               if (Fl::event_x() >= points.at(i).x+x()-3 &&
+                               Fl::event_x() <= points.at(i).x+x()+3)
+               return i;
+       }
+       return -1;
+}
diff --git a/src/gui/elems/muteEditor.h b/src/gui/elems/muteEditor.h
new file mode 100644 (file)
index 0000000..620f82a
--- /dev/null
@@ -0,0 +1,106 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_MUTECHANNEL_H
+#define GE_MUTECHANNEL_H
+
+
+#include <vector>
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include <FL/fl_draw.H>
+#include "../../utils/fs.h"
+#include "baseActionEditor.h"
+
+
+using std::vector;
+
+
+class geMuteEditor : public geBaseActionEditor
+{
+private:
+
+       /* point
+        * a single dot in the graph. */
+
+       struct point
+       {
+               int  frame;
+               char type;
+               int  x;
+       };
+
+       /* points
+        * array of on/off points, in frames */
+
+       vector<point> points;
+
+       /* draggedPoint
+        * which point we are dragging? */
+
+       int draggedPoint;
+
+       /* selectedPoint
+        * which point we are selecting? */
+
+       int selectedPoint;
+
+       /* previousXPoint
+        * x coordinate of point at time t-1. Used to check effective shifts */
+
+       int previousXPoint;
+
+       /* extractPoints
+        * va a leggere l'array di azioni di Recorder ed estrae tutti i punti
+        * interessanti mute_on o mute_off. Li mette poi nel vector points. */
+       void extractPoints();
+
+       /* getSelectedPoint
+        * ritorna l'indice di points[] in base al punto selezionato (quello
+        * con il mouse hover). Ritorna -1 se non trova niente. */
+       int getSelectedPoint();
+
+       /* pointCollides
+        * true if a point collides with another. Used while adding new points
+        * with snap active.*/
+
+       bool pointCollides(int frame);
+
+public:
+
+       geMuteEditor(int x, int y, class gdActionEditor *pParent);
+       void draw();
+       int  handle(int e);
+
+       /* updateActions
+        * calculates new points affected by the zoom. Call this one after
+        * each zoom update. */
+
+       void updateActions();
+};
+
+#endif
diff --git a/src/gui/elems/noteEditor.cpp b/src/gui/elems/noteEditor.cpp
new file mode 100644 (file)
index 0000000..19940a2
--- /dev/null
@@ -0,0 +1,90 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/fl_draw.H>
+#include "../../core/const.h"
+#include "../../core/conf.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "pianoItem.h"
+#include "pianoRoll.h"
+#include "noteEditor.h"
+
+
+extern Conf G_Conf;
+
+
+geNoteEditor::geNoteEditor(int x, int y, gdActionEditor *pParent)
+  : Fl_Scroll(x, y, 200, 422),
+    pParent  (pParent)
+{
+       size(pParent->totalWidth, G_Conf.pianoRollH);
+       pianoRoll = new gePianoRoll(x, y, pParent->totalWidth, pParent);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+geNoteEditor::~geNoteEditor()
+{
+       clear();
+       G_Conf.pianoRollH = h();
+       G_Conf.pianoRollY = pianoRoll->y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geNoteEditor::updateActions()
+{
+       pianoRoll->updateActions();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geNoteEditor::draw()
+{
+       pianoRoll->size(this->w(), pianoRoll->h());  /// <--- not optimal
+
+       /* clear background */
+
+       fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN);
+
+       /* clip pianoRoll to pianoRollContainer size */
+
+       fl_push_clip(x(), y(), w(), h());
+       draw_child(*pianoRoll);
+       fl_pop_clip();
+
+       fl_color(COLOR_BD_0);
+       fl_line_style(0);
+       fl_rect(x(), y(), pParent->totalWidth, h());
+}
diff --git a/src/gui/elems/noteEditor.h b/src/gui/elems/noteEditor.h
new file mode 100644 (file)
index 0000000..0ca600f
--- /dev/null
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_NOTE_EDITOR_H
+#define GE_NOTE_EDITOR_H
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Box.H>
+#include "../../core/recorder.h"
+
+
+class geNoteEditor : public Fl_Scroll
+{
+private:
+
+       class gdActionEditor *pParent;
+       class gePianoRoll    *pianoRoll;
+
+public:
+
+       geNoteEditor(int x, int y, class gdActionEditor *parent);
+       ~geNoteEditor();
+       void draw();
+       void updateActions();
+};
+
+
+#endif
diff --git a/src/gui/elems/pianoItem.cpp b/src/gui/elems/pianoItem.cpp
new file mode 100644 (file)
index 0000000..870b61a
--- /dev/null
@@ -0,0 +1,348 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/kernelMidi.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../../core/midiChannel.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "noteEditor.h"
+#include "pianoRoll.h"
+#include "pianoItem.h"
+
+
+extern KernelMidi G_KernelMidi;
+extern Mixer      G_Mixer;
+extern Recorder          G_Recorder;
+
+
+gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, Recorder::action *_a,
+  Recorder::action *_b, gdActionEditor *pParent)
+       : Fl_Box  (X, Y, MIN_WIDTH, gePianoRoll::CELL_H),
+         a       (_a),
+         b       (_b),
+               pParent (pParent),
+               selected(false),
+               event_a (0x00),
+               event_b (0x00),
+               changed (false)
+{
+       /* a is a pointer: action exists, needs to be displayed */
+
+       if (a) {
+               note    = G_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());
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gePianoItem::overlap()
+{
+       /* when 2 segments overlap?
+        * start = the highest value between the two starting points
+        * end   = the lowest value between the two ending points
+        * if start < end then there's an overlap of end-start pixels. */
+
+       geNoteEditor *pPiano = (geNoteEditor*) parent();
+
+       for (int i=0; i<pPiano->children(); i++) {
+
+               gePianoItem *pItem = (gePianoItem*) pPiano->child(i);
+
+               /* don't check against itself and with different y positions */
+
+               if (pItem == this || pItem->y() != y())
+                       continue;
+
+               int start = pItem->x() >= x() ? pItem->x() : x();
+               int end   = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w();
+               if (start < end)
+                       return true;
+       }
+
+       return false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoItem::draw()
+{
+       int _w = w() > MIN_WIDTH ? w() : MIN_WIDTH;
+       fl_rectf(x(), y()+2, _w, h()-3, (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoItem::record()
+{
+       /* avoid frame overflow */
+
+       int overflow = frame_b - G_Mixer.totalFrames;
+       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);
+
+       G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a);
+       G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoItem::remove()
+{
+       G_Recorder.deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0);
+       G_Recorder.deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0);
+
+       /* send a note-off in case we are deleting it in a middle of a key_on
+        * key_off sequence. */
+
+       ((MidiChannel*) pParent->chan)->sendMidi(event_b);
+
+  ((gePianoRoll*) parent())->cursorOnItem = false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoItem::handle(int e)
+{
+       int ret = 0;
+
+       switch (e) {
+
+               case FL_ENTER: {
+      ((gePianoRoll*) parent())->cursorOnItem = true;
+                       selected = true;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+
+               case FL_LEAVE: {
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+      ((gePianoRoll*) parent())->cursorOnItem = false;
+                       selected = false;
+                       ret = 1;
+                       redraw();
+                       break;
+               }
+
+               case FL_MOVE: {
+                       onLeftEdge  = false;
+                       onRightEdge = false;
+
+                       if (Fl::event_x() >= x() && Fl::event_x() < x()+HANDLE_WIDTH) {
+                               onLeftEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       }
+                       else
+                       if (Fl::event_x() >= x()+w()-HANDLE_WIDTH && Fl::event_x() <= x()+w()) {
+                               onRightEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       }
+                       else
+                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+
+                       ret = 1;
+                       break;
+               }
+
+               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();
+                               hide();   // for Windows
+                               Fl::delete_widget(this);
+                               ((geNoteEditor*)parent())->redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+
+               case FL_DRAG: {
+
+                       changed = true;
+
+                       geNoteEditor *pr = (geNoteEditor*) parent();
+                       int coverX     = pParent->coverX + pr->x(); // relative coverX
+                       int nx, ny, nw;
+
+                       if (onLeftEdge) {
+                               nx = Fl::event_x();
+                               ny = y();
+                               nw = x()-Fl::event_x()+w();
+                               if (nx < pr->x()) {
+                                       nx = pr->x();
+                                       nw = w()+x()-pr->x();
+                               }
+                               else
+                               if (nx > x()+w()-MIN_WIDTH) {
+                                       nx = x()+w()-MIN_WIDTH;
+                                       nw = MIN_WIDTH;
+                               }
+                               resize(nx, ny, nw, h());
+                       }
+                       else
+                       if (onRightEdge) {
+                               nw = Fl::event_x()-x();
+                               if (Fl::event_x() < x()+MIN_WIDTH)
+                                       nw = MIN_WIDTH;
+                               else
+                               if (Fl::event_x() > coverX)
+                                       nw = coverX-x();
+                               size(nw, h());
+                       }
+                       else {
+                               nx = Fl::event_x() - push_x;
+                               if (nx < pr->x()+1)
+                                       nx = pr->x()+1;
+                               else
+                               if (nx+w() > coverX)
+                                       nx = coverX-w();
+
+                               /* snapping */
+
+                               if (pParent->gridTool->isOn())
+                                       nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1;
+
+                               position(nx, y());
+                       }
+
+                       /* update screen */
+
+                       redraw();
+                       ((geNoteEditor*)parent())->redraw();
+                       ret = 1;
+                       break;
+               }
+
+               case FL_RELEASE: {
+
+                       /* delete & record the action, only if it doesn't overlap with
+                        * another one */
+
+                       if (overlap()) {
+                               resize(old_x, y(), old_w, h());
+                               redraw();
+                       }
+                       else
+                       if (changed) {
+                               remove();
+                               note    = getNote(getRelY());
+                               frame_a = getRelX() * pParent->zoom;
+                               frame_b = (getRelX()+w()) * pParent->zoom;
+                               record();
+                               changed = false;
+                       }
+
+                       ((geNoteEditor*)parent())->redraw();
+
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoItem::getNote(int rel_y)
+{
+  return gePianoRoll::MAX_KEYS - (rel_y / gePianoRoll::CELL_H);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoItem::getRelY()
+{
+  return y() - parent()->y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoItem::getRelX()
+{
+  return x() - parent()->x();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoItem::getY(int note)
+{
+  return (gePianoRoll::MAX_KEYS * gePianoRoll::CELL_H) - (note * gePianoRoll::CELL_H);
+}
diff --git a/src/gui/elems/pianoItem.h b/src/gui/elems/pianoItem.h
new file mode 100644 (file)
index 0000000..0aa4b2b
--- /dev/null
@@ -0,0 +1,119 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_PIANO_ITEM_H
+#define GE_PIANO_ITEM_H
+
+
+#include <FL/Fl_Box.H>
+#include "../../core/recorder.h"
+
+
+class gePianoItem : public Fl_Box
+{
+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);
+
+       /* getY
+        * from a note, return the y position on piano roll */
+
+       int getY(int note);
+
+       /* overlap
+        * check if this item don't overlap with another one. */
+
+       bool overlap();
+
+       struct Recorder::action *a;
+       struct Recorder::action *b;
+       class gdActionEditor *pParent;
+
+       bool selected;
+       int  push_x;
+
+       /* MIDI note, start frame, end frame - Used only if it's a newly added
+        * action */ /** FIXME - is it true? */
+
+       int  note;
+       int  frame_a;
+       int  frame_b;
+
+       /* 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 */
+
+       bool changed;
+
+       /* 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 */
+
+       int old_x, old_w;
+
+public:
+
+       static const int MIN_WIDTH    = 10;
+       static const int HANDLE_WIDTH = 5;
+
+       /* pianoItem ctor
+        * if action *a == NULL, record a new action */
+
+       gePianoItem(int x, int y, int rel_x, int rel_y, struct Recorder::action *a,
+               struct Recorder::action *b, class gdActionEditor *pParent);
+
+       void draw();
+       int  handle(int e);
+       void record();
+       void remove();
+
+       int getFrame_a() { return frame_a; }
+       int getFrame_b() { return frame_b; }
+       int getNote()    { return note;    }
+};
+
+
+#endif
diff --git a/src/gui/elems/pianoRoll.cpp b/src/gui/elems/pianoRoll.cpp
new file mode 100644 (file)
index 0000000..b8f776b
--- /dev/null
@@ -0,0 +1,360 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/conf.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../../core/recorder.h"
+#include "../../core/kernelMidi.h"
+#include "../../utils/log.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "pianoItem.h"
+#include "noteEditor.h"
+#include "pianoRoll.h"
+
+
+extern Conf          G_Conf;
+extern Recorder                G_Recorder;
+extern Mixer      G_Mixer;
+extern KernelMidi G_KernelMidi;
+
+
+gePianoRoll::gePianoRoll(int X, int Y, int W, gdActionEditor *pParent)
+  : geBaseActionEditor(X, Y, W, 40, pParent),
+    cursorOnItem      (false)
+{
+       resizable(nullptr);                   // don't resize children (i.e. pianoItem)
+       size(W, (MAX_KEYS+1) * CELL_H);      // 128 MIDI channels * CELL_H height
+
+       if (G_Conf.pianoRollY == -1)
+               position(x(), y()-(h()/2));  // center
+       else
+               position(x(), G_Conf.pianoRollY);
+
+       drawSurface1();
+       drawSurface2();
+
+       /* add actions when the window is opened. Position is zoom-based. MIDI
+        * actions come always in pair: start + end. */
+
+       G_Recorder.sortActions();
+
+       Recorder::action *a2   = nullptr;
+       Recorder::action *prev = nullptr;
+
+       for (unsigned i=0; i<G_Recorder.frames.size(); i++) {
+               for (unsigned j=0; j<G_Recorder.global.at(i).size(); j++) {
+
+                       /* don't show actions > than the grey area */
+                       /** FIXME - can we move this to the outer cycle? */
+
+                       if (G_Recorder.frames.at(i) > G_Mixer.totalFrames)
+                               continue;
+
+                       Recorder::action *a1 = G_Recorder.global.at(i).at(j);
+
+      /* Skip action if:
+        - does not belong to this channel
+        - is not a MIDI action (we only want MIDI things here)
+        - is the previous one (we have already checked it)
+        - (later on) if it's NOTE_OFF (0x80): we want note on only */
+
+      if (a1->chan != pParent->chan->index)
+                               continue;
+      if (a1->type != ACTION_MIDI)
+        continue;
+                       if (a1 == prev)
+                               continue;
+
+                       /* extract MIDI infos from a1: if is note off skip it, we are looking
+                        * for note on only */
+
+                       int a1_type = G_KernelMidi.getB1(a1->iValue);
+                       int a1_note = G_KernelMidi.getB2(a1->iValue);
+
+                       if (a1_type == 0x80) // NOTE_OFF
+                               continue;
+
+                       /* Search for the next action. Must have: same channel, 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. */
+
+                       G_Recorder.getNextAction(a1->chan, ACTION_MIDI, a1->frame, &a2,
+                                       G_KernelMidi.getIValue(0x80, a1_note, 0xFF));
+
+                       /* next action note_off found: add a new gePianoItem to piano roll */
+
+                       if (a2) {
+                               new gePianoItem(0, 0, x(), y(), a1, a2, pParent);
+                               prev = a2;
+                               a2 = nullptr;
+                       }
+                       else
+                               gu_log("[geNoteEditor] recorder didn't find requested action!\n");
+        // TODO - create new gOrphanedPianoItem
+         }
+       }
+
+       end();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoRoll::drawSurface1()
+{
+       surface1 = fl_create_offscreen(CELL_W, h());
+       fl_begin_offscreen(surface1);
+
+       /* warning: only w() and h() come from this widget, x and y coordinates
+        * are absolute, since we are writing in a memory chunk */
+
+       fl_rectf(0, 0, CELL_W, h(), COLOR_BG_MAIN);
+
+       fl_line_style(FL_DASH, 0, nullptr);
+       fl_font(FL_HELVETICA, GUI_FONT_SIZE_BASE);
+
+       int octave = MAX_OCTAVES;
+
+       for (int i=1; i<=MAX_KEYS+1; i++) {
+
+               /* print key note label. C C# D D# E F F# G G# A A# B */
+
+               char note[6];
+               switch (i % KEYS) {
+                       case (int) Notes::G:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               sprintf(note, "%dG", octave);
+                               break;
+                       case (int) Notes::FS:
+                               sprintf(note, "%dF#", octave);
+                               break;
+                       case (int) Notes::F:
+                               sprintf(note, "%dF", octave);
+                               break;
+                       case (int) Notes::E:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               sprintf(note, "%dE", octave);
+                               break;
+                       case (int) Notes::DS:
+                               sprintf(note, "%dD#", octave);
+                               break;
+                       case (int) Notes::D:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               sprintf(note, "%dD", octave);
+                               break;
+                       case (int) Notes::CS:
+                               sprintf(note, "%dC#", octave);
+                               break;
+                       case (int) Notes::C:
+                               sprintf(note, "%dC", octave);
+                               break;
+                       case (int) Notes::B:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               sprintf(note, "%dB", octave);
+                               break;
+                       case (int) Notes::AS:
+                               sprintf(note, "%dA#", octave);
+                               break;
+                       case (int) Notes::A:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               sprintf(note, "%dA", octave);
+                               break;
+                       case (int) Notes::GS:
+                               sprintf(note, "%dG#", octave);
+                               octave--;
+                               break;
+               }
+
+    /* Print note name */
+
+               fl_color(COLOR_BG_LINE);
+               fl_draw(note, 4, ((i-1)*CELL_H)+1, CELL_W, CELL_H,
+      (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+
+               /* Print horizontal line */
+
+               if (i < MAX_KEYS+1)
+                       fl_line(0, i*CELL_H, CELL_W, +i*CELL_H);
+       }
+
+       fl_line_style(0);
+       fl_end_offscreen();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoRoll::drawSurface2()
+{
+       surface2 = fl_create_offscreen(CELL_W, h());
+       fl_begin_offscreen(surface2);
+       fl_rectf(0, 0, CELL_W, h(), COLOR_BG_MAIN);
+       fl_color(COLOR_BG_LINE);
+       fl_line_style(FL_DASH, 0, nullptr);
+       for (int i=1; i<=MAX_KEYS+1; i++) {
+               switch (i % KEYS) {
+                       case (int) Notes::G:
+                       case (int) Notes::E:
+                       case (int) Notes::D:
+                       case (int) Notes::B:
+                       case (int) Notes::A:
+                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH);
+                               break;
+               }
+               if (i < MAX_KEYS+1) {
+                       fl_color(COLOR_BG_LINE);
+                       fl_line(0, i*CELL_H, CELL_W, i*CELL_H);
+               }
+       }
+       fl_line_style(0);
+       fl_end_offscreen();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoRoll::draw()
+{
+       fl_copy_offscreen(x(), y(), CELL_W, h(), surface1, 0, 0);
+
+#if defined(__APPLE__)
+       for (int i=36; i<pParent->totalWidth; i+=36) /// TODO: i < pParent->coverX is faster
+               fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 1, 0);
+#else
+       for (int i=CELL_W; i<pParent->totalWidth; i+=CELL_W) /// TODO: i < pParent->coverX is faster
+               fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 0, 0);
+#endif
+
+       baseDraw(false);
+       draw_children();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoRoll::handle(int e)
+{
+       int ret = Fl_Group::handle(e);
+
+       switch (e) {
+               case FL_PUSH:   {
+
+                       /* avoid click on grey area */
+
+                       if (Fl::event_x() >= pParent->coverX) {
+                               ret = 1;
+                               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 */
+
+                               int ax = Fl::event_x();
+                               int ay = Fl::event_y();
+
+                               /* 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();
+                               }
+                       }
+                       ret = 1;
+                       break;
+               }
+               case FL_DRAG:   {
+
+                       if (Fl::event_button3()) {
+
+                               geNoteEditor *prc = (geNoteEditor*) parent();
+                               position(x(), Fl::event_y() - push_y);
+
+                               if (y() > prc->y())
+                                       position(x(), prc->y());
+                               else
+                               if (y() < prc->y()+prc->h()-h())
+                                       position(x(), prc->y()+prc->h()-h());
+
+                               prc->redraw();
+                       }
+                       ret = 1;
+                       break;
+               }
+               case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePianoRoll::updateActions()
+{
+       /* when zooming, don't delete and re-add actions, just MOVE them. This
+        * function shifts the action by a zoom factor. Those singlepress are
+        * stretched, as well */
+
+       gePianoItem *i;
+       for (int k=0; k<children(); k++) {
+               i = (gePianoItem*) child(k);
+
+               //gu_log("found point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
+
+               int newX = x() + (i->getFrame_a() / pParent->zoom);
+               int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom);
+               if (newW < 8)
+                       newW = 8;
+               i->resize(newX, i->y(), newW, i->h());
+               i->redraw();
+
+               //gu_log("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x());
+       }
+}
diff --git a/src/gui/elems/pianoRoll.h b/src/gui/elems/pianoRoll.h
new file mode 100644 (file)
index 0000000..449d4d0
--- /dev/null
@@ -0,0 +1,84 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_PIANO_ROLL_H
+#define GE_PIANO_ROLL_H
+
+
+#include <FL/fl_draw.H>
+#include "baseActionEditor.h"
+
+
+class gePianoRoll : public geBaseActionEditor
+{
+private:
+
+       enum class Notes
+       {
+               G = 1, FS = 2, F = 3, E = 4, DS = 5, D = 6, CS = 7, C = 8, B = 9, AS = 10,
+               A = 11, GS = 0
+       };
+
+       /* drawSurface*
+       Generates a complex drawing in memory first and copy it to the screen at a
+       later point in time. Fl_Offscreen surface holds the necessary data.     The first
+       call creates an offscreen surface of CELL_W pixel wide containing note values.
+       The second call creates another offscreen surface of CELL_W pixels wide
+       containing the rest of the piano roll. The latter will then be tiled during
+       the ::draw() call. */
+
+       void drawSurface1();
+       void drawSurface2();
+
+       int push_y;
+
+       Fl_Offscreen surface1;  // notes, no repeat
+       Fl_Offscreen surface2;  // lines, x-repeat
+
+public:
+
+       static const int MAX_KEYS    = 127;
+       static const int MAX_OCTAVES = 9;
+       static const int KEYS        = 12;
+       static const int CELL_H      = 18;
+       static const int CELL_W      = 40;
+
+       gePianoRoll(int x, int y, int w, class gdActionEditor *pParent);
+
+       void draw();
+       int  handle(int e);
+       void updateActions();
+
+       /* cursorOnItem
+       Defines wheter the cursor is over a piano item. This value is updated by each
+       gePianoItem sub-widget. */
+
+       bool cursorOnItem;
+};
+
+
+#endif
diff --git a/src/gui/elems/sampleChannel.cpp b/src/gui/elems/sampleChannel.cpp
new file mode 100644 (file)
index 0000000..5b7e4c9
--- /dev/null
@@ -0,0 +1,512 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_sampleChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../../core/pluginHost.h"
+#include "../../core/mixer.h"
+#include "../../core/conf.h"
+#include "../../core/patch_DEPR_.h"
+#include "../../core/recorder.h"
+#include "../../core/graphics.h"
+#include "../../core/wave.h"
+#include "../../glue/main.h"
+#include "../../glue/io.h"
+#include "../../glue/channel.h"
+#include "../../glue/storage.h"
+#include "../../utils/gui.h"
+#include "../../utils/string.h"
+#include "../dialogs/gd_mainWindow.h"
+#include "../dialogs/gd_keyGrabber.h"
+#include "../dialogs/gd_midiOutput.h"
+#include "../dialogs/gd_midiInput.h"
+#include "../dialogs/gd_editor.h"
+#include "../dialogs/gd_actionEditor.h"
+#include "../dialogs/gd_warnings.h"
+#include "../dialogs/gd_browser.h"
+#include "ge_status.h"
+#include "ge_modeBox.h"
+#include "ge_keyboard.h"
+#include "sampleChannel.h"
+
+
+extern Mixer                G_Mixer;
+extern Conf                 G_Conf;
+extern Recorder                         G_Recorder;
+extern Patch_DEPR_   G_Patch_DEPR_;
+extern gdMainWindow *G_MainWin;
+
+
+geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch)
+       : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch)
+{
+       begin();
+
+       button      = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
+       arm         = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
+       status      = new gStatus(arm->x()+arm->w()+4, y(), 20, 20, ch);
+       mainButton  = new geSampleChannelButton(status->x()+status->w()+4, y(), 20, 20, "-- no sample --");
+       readActions = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm);
+       modeBox     = new gModeBox(readActions->x()+readActions->w()+4, y(), 20, 20, ch);
+       mute        = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
+       solo        = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+#ifdef WITH_VST
+       fx          = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
+       vol         = new gDial(fx->x()+fx->w()+4, y(), 20, 20);
+#else
+       vol         = new gDial(solo->x()+solo->w()+4, y(), 20, 20);
+#endif
+
+       end();
+
+  resizable(mainButton);
+
+       update();
+
+       button->callback(cb_button, (void*)this);
+       button->when(FL_WHEN_CHANGED);   // do callback on keypress && on keyrelease
+
+       arm->type(FL_TOGGLE_BUTTON);
+       arm->callback(cb_arm, (void*)this);
+
+#ifdef WITH_VST
+       fx->callback(cb_openFxWindow, (void*)this);
+#endif
+
+       mute->type(FL_TOGGLE_BUTTON);
+       mute->callback(cb_mute, (void*)this);
+
+       solo->type(FL_TOGGLE_BUTTON);
+       solo->callback(cb_solo, (void*)this);
+
+       mainButton->callback(cb_openMenu, (void*)this);
+
+       readActions->type(FL_TOGGLE_BUTTON);
+       readActions->value(ch->readActions);
+       readActions->callback(cb_readActions, (void*)this);
+
+       vol->callback(cb_changeVol, (void*)this);
+
+       ch->guiChannel = this;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::cb_button      (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); }
+void geSampleChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); }
+void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::__cb_button()
+{
+       if (button->value())    // pushed
+               glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
+       else                    // released
+               glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+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 (G_Mixer.recording || G_Recorder.active)
+               return;
+
+       /* the following is a trash workaround for a FLTK menu. We need a gMenu
+        * widget asap */
+
+       Fl_Menu_Item rclick_menu[] = {
+               {"Load new sample..."},                     // 0
+               {"Export sample to file..."},               // 1
+               {"Setup keyboard input..."},                // 2
+               {"Setup MIDI input..."},                    // 3
+               {"Setup MIDI output..."},                   // 4
+               {"Edit sample..."},                         // 5
+               {"Edit actions..."},                        // 6
+               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 7
+                       {"All"},                                  // 8
+                       {"Mute"},                                 // 9
+                       {"Volume"},                               // 10
+                       {"Start/Stop"},                           // 11
+                       {0},                                      // 12
+               {"Clone channel"},                          // 13
+               {"Free channel"},                           // 14
+               {"Delete channel"},                         // 15
+               {0}
+       };
+
+       if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) {
+               rclick_menu[1].deactivate();
+               rclick_menu[5].deactivate();
+               rclick_menu[14].deactivate();
+       }
+
+       /* no 'clear actions' if there are no actions */
+
+       if (!ch->hasActions)
+               rclick_menu[7].deactivate();
+
+       /* no 'clear start/stop actions' for those channels in loop mode:
+        * they cannot have start/stop actions. */
+
+       if (((SampleChannel*)ch)->mode & LOOP_ANY)
+               rclick_menu[11].deactivate();
+
+       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       b->box(G_BOX);
+       b->textsize(GUI_FONT_SIZE_BASE);
+       b->textcolor(COLOR_TEXT_0);
+       b->color(COLOR_BG_0);
+
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (!m) return;
+
+       if (strcmp(m->label(), "Load new sample...") == 0) {
+               openBrowser(BROWSER_LOAD_SAMPLE);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup keyboard input...") == 0) {
+               new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh((SampleChannel*) ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit sample...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdEditor((SampleChannel*) ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor
+               return;
+       }
+
+       if (strcmp(m->label(), "Export sample to file...") == 0) {
+               openBrowser(BROWSER_SAVE_SAMPLE);
+               return;
+       }
+
+       if (strcmp(m->label(), "Delete channel") == 0) {
+               if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+                       return;
+               glue_deleteChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Free channel") == 0) {
+               if (ch->status == STATUS_PLAY) {
+                       if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
+                               return;
+               }
+               else if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
+                       return;
+
+               glue_freeChannel(ch);
+
+               /* delete any related subwindow */
+
+               /** FIXME - use gu_closeAllSubwindows() */
+
+               G_MainWin->delSubWindow(WID_FILE_BROWSER);
+               G_MainWin->delSubWindow(WID_ACTION_EDITOR);
+               G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
+               G_MainWin->delSubWindow(WID_FX_LIST);
+
+               return;
+       }
+
+       if (strcmp(m->label(), "Clone channel") == 0) {
+               glue_cloneChannel(ch);
+               return;
+       }
+
+       if (strcmp(m->label(), "Mute") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
+                       return;
+               G_Recorder.clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF);
+               if (!ch->hasActions)
+                       hideActionButton();
+
+               /* TODO - set mute=false */
+
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Start/Stop") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
+                       return;
+               G_Recorder.clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN);
+               if (!ch->hasActions)
+                       hideActionButton();
+               gu_refreshActionEditor();  // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Volume") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
+                       return;
+               G_Recorder.clearAction(ch->index, ACTION_VOLUME);
+               if (!ch->hasActions)
+                       hideActionButton();
+               gu_refreshActionEditor();  // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "All") == 0) {
+               if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+                       return;
+               G_Recorder.clearChan(ch->index);
+               hideActionButton();
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
+               return;
+       }
+
+       if (strcmp(m->label(), "Edit actions...") == 0) {
+               gu_openSubWindow(G_MainWin, new gdActionEditor(ch),     WID_ACTION_EDITOR);
+               return;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::__cb_readActions()
+{
+       glue_startStopReadingRecs((SampleChannel*) ch);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::openBrowser(int type)
+{
+       gWindow *childWin = NULL;
+       switch (type) {
+               case BROWSER_LOAD_SAMPLE:
+                       childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY,
+                                       G_Conf.browserW, G_Conf.browserH, "Browse sample",
+                                       G_Conf.samplePath.c_str(), glue_loadSample, ch);
+                       break;
+               case BROWSER_SAVE_SAMPLE:
+                       childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY,
+                                       G_Conf.browserW, G_Conf.browserH, "Save sample", \
+                                       G_Conf.samplePath.c_str(), "", glue_saveSample, ch);
+                       break;
+       }
+       if (childWin)
+               gu_openSubWindow(G_MainWin, childWin,   WID_FILE_BROWSER);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::refresh()
+{
+  if (!mainButton->visible()) // mainButton invisible? status too (see below)
+    return;
+
+       setColorsByStatus(ch->status, ch->recStatus);
+
+       if (((SampleChannel*) ch)->wave != NULL) {
+               if (G_Mixer.recording && ch->armed)
+                       mainButton->setInputRecordMode();
+               if (G_Recorder.active) {
+                       if (G_Recorder.canRec(ch))
+                               mainButton->setActionRecordMode();
+               }
+               status->redraw(); // status invisible? sampleButton too (see below)
+       }
+       mainButton->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::reset()
+{
+       hideActionButton();
+       mainButton->setDefaultMode("-- no sample --");
+       mainButton->redraw();
+       status->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::update()
+{
+       /* update sample button's label */
+
+       switch (ch->status) {
+               case STATUS_EMPTY:
+                       mainButton->label("-- no sample --");
+                       break;
+               case STATUS_MISSING:
+               case STATUS_WRONG:
+                       mainButton->label("* file not found! *");
+                       break;
+               default:
+                       mainButton->label(((SampleChannel*) ch)->wave->name.c_str());
+                       break;
+       }
+
+       /* update channels. If you load a patch with recorded actions, the 'R'
+        * button must be shown. Moreover if the actions are active, the 'R'
+        * button must be activated accordingly. */
+
+       if (ch->hasActions)
+               showActionButton();
+       else
+               hideActionButton();
+
+       /* updates modebox */
+
+       modeBox->value(((SampleChannel*) ch)->mode);
+       modeBox->redraw();
+
+       /* update volumes+mute+solo */
+
+       vol->value(ch->volume);
+       mute->value(ch->mute);
+       solo->value(ch->solo);
+
+       mainButton->setKey(ch->key);
+
+#ifdef WITH_VST
+       fx->full = ch->plugins.size() > 0;
+       fx->redraw();
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::showActionButton()
+{
+       readActions->value(((SampleChannel*) ch)->readActions);
+       readActions->show();
+       packWidgets();
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::hideActionButton()
+{
+       readActions->hide();
+       packWidgets();
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleChannel::resize(int X, int Y, int W, int H)
+{
+  geChannel::resize(X, Y, W, H);
+
+       arm->hide();
+       modeBox->hide();
+       readActions->hide();
+#ifdef WITH_VST
+       fx->hide();
+#endif
+
+       if (w() > BREAK_ARM)
+               arm->show();
+#ifdef WITH_VST
+       if (w() > BREAK_FX)
+               fx->show();
+#endif
+       if (w() > BREAK_MODE_BOX)
+               modeBox->show();
+       if (w() > BREAK_READ_ACTIONS && ch->hasActions)
+               readActions->show();
+
+       packWidgets();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const char *l)
+       : geChannelButton(x, y, w, h, l) {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geSampleChannelButton::handle(int e)
+{
+       int ret = gClick::handle(e);
+       switch (e) {
+               case FL_DND_ENTER:
+               case FL_DND_DRAG:
+               case FL_DND_RELEASE: {
+                       ret = 1;
+                       break;
+               }
+               case FL_PASTE: {
+      geSampleChannel *gch = (geSampleChannel*) parent();   // parent is geSampleChannel
+      SampleChannel   *ch  = (SampleChannel*) gch->ch;
+      int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str());
+                       if (result != SAMPLE_LOADED_OK)
+                               G_MainWin->keyboard->printChannelMessage(result);
+                       ret = 1;
+                       break;
+               }
+       }
+       return ret;
+}
diff --git a/src/gui/elems/sampleChannel.h b/src/gui/elems/sampleChannel.h
new file mode 100644 (file)
index 0000000..efde2a6
--- /dev/null
@@ -0,0 +1,83 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_sampleChannel
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_SAMPLE_CHANNEL_H
+#define GE_SAMPLE_CHANNEL_H
+
+
+#include "channel.h"
+#include "channelButton.h"
+
+
+class geSampleChannel : public geChannel
+{
+private:
+
+       static void cb_button        (Fl_Widget *v, void *p);
+       static void cb_openMenu      (Fl_Widget *v, void *p);
+       static void cb_readActions   (Fl_Widget *v, void *p);
+
+       inline void __cb_button      ();
+       inline void __cb_openMenu    ();
+       inline void __cb_readActions ();
+
+       void openBrowser(int type);
+
+public:
+
+       geSampleChannel(int x, int y, int w, int h, class SampleChannel *ch);
+
+       void reset   ();
+       void update  ();
+       void refresh ();
+       void resize  (int x, int y, int w, int h);
+
+       /* show/hideActionButton
+       Adds or removes 'R' button when actions are available. */
+
+       void showActionButton();
+       void hideActionButton();
+
+       class gModeBox *modeBox;
+       class gClick     *readActions;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class geSampleChannelButton : public geChannelButton
+{
+public:
+       geSampleChannelButton(int x, int y, int w, int h, const char *l=0);
+       int handle(int e);
+};
+
+
+#endif
index d619c5a0b365b5303cd0a0021d9bf8a302422150..a80e63be53c008d1d650981544493f5c68646326 100644 (file)
 #include "core/mixer.h"
 #include "core/mixerHandler.h"
 #include "core/kernelAudio.h"
+#include "core/kernelMidi.h"
 #include "core/recorder.h"
-#include "utils/gui_utils.h"
+#include "utils/gui.h"
 #include "gui/dialogs/gd_mainWindow.h"
 #include "core/pluginHost.h"
 
 
 /* global variables. Yeah, we are nasty */
 
-pthread_t     t_video;
+pthread_t     G_videoThread;
+KernelAudio   G_KernelAudio;
 Mixer         G_Mixer;
+Recorder      G_Recorder;
+KernelMidi    G_KernelMidi;
 bool          G_quit;
 bool           G_audio_status;
 bool          G_midiStatus;
@@ -55,18 +59,18 @@ Patch_DEPR_   G_Patch_DEPR_;
 Patch         G_Patch;
 Conf          G_Conf;
 MidiMapConf   G_MidiMap;
-gdMainWindow *mainWin;
+gdMainWindow *G_MainWin;
 
 #ifdef WITH_VST
 PluginHost G_PluginHost;
 #endif
 
 
-void *thread_video(void *arg);
+void *videoThreadCb(void *arg);
 
 
-int main(int argc, char **argv) {
-
+int main(int argc, char **argv)
+{
        G_quit = false;
 
        init_prepareParser();
@@ -75,7 +79,7 @@ int main(int argc, char **argv) {
        init_prepareKernelMIDI();
        init_startGUI(argc, argv);
        Fl::lock();
-       pthread_create(&t_video, NULL, thread_video, NULL);
+       pthread_create(&G_videoThread, NULL, videoThreadCb, NULL);
        init_startKernelAudio();
 
 #ifdef WITH_VST
@@ -88,16 +92,16 @@ int main(int argc, char **argv) {
        juce::shutdownJuce_GUI();
 #endif
 
-       pthread_join(t_video, NULL);
+       pthread_join(G_videoThread, NULL);
        return ret;
 }
 
 
-
-void *thread_video(void *arg) {
+void *videoThreadCb(void *arg)
+{
        if (G_audio_status)
                while (!G_quit) {
-                       gu_refresh();
+                       gu_refreshUI();
 #ifdef _WIN32
                        Sleep(GUI_SLEEP);
 #else
diff --git a/src/utils/fs.cpp b/src/utils/fs.cpp
new file mode 100644 (file)
index 0000000..23b2384
--- /dev/null
@@ -0,0 +1,267 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#if defined(_WIN32)                    // getcwd (unix) or __getcwd (win)
+       #include <direct.h>
+       #include <windows.h>
+#else
+       #include <unistd.h>
+#endif
+
+#include <cstdarg>
+#include <sys/stat.h>   // stat (gu_dirExists)
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string>
+#include <string.h>
+#include <limits.h>
+#if defined(__APPLE__)
+       #include <libgen.h>     // basename unix
+       #include <pwd.h>        // getpwuid
+#endif
+#include "../core/const.h"
+#include "string.h"
+#include "log.h"
+#include "fs.h"
+
+
+using std::string;
+using std::vector;
+
+
+bool gu_fileExists(const string &filename)
+{
+       FILE *fh = fopen(filename.c_str(), "rb");
+       if (!fh) {
+               return 0;
+       }
+       else {
+               fclose(fh);
+               return 1;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gu_isDir(const string &path)
+{
+       bool ret;
+
+#if defined(__linux__)
+
+       struct stat s1;
+       stat(path.c_str(), &s1);
+       ret = S_ISDIR(s1.st_mode);
+
+#elif defined(__APPLE__)
+
+       if (strcmp(path.c_str(), "") == 0)
+               ret = false;
+       else {
+               struct stat s1;
+               stat(path.c_str(), &s1);
+               ret = S_ISDIR(s1.st_mode);
+
+               /* check if ret is a bundle, a special OS X folder which must be
+                * shown as a regular file (VST).
+                * FIXME - consider native functions CFBundle... */
+
+               if (ret) {
+                       if (gu_fileExists(path + "/Contents/Info.plist"))
+                               ret = false;
+               }
+       }
+
+#elif defined(__WIN32)
+
+  unsigned dwAttrib = GetFileAttributes(path.c_str());
+  ret = (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+        (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
+#endif
+
+       return ret & !gu_isProject(path);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gu_dirExists(const string &path)
+{
+       struct stat st;
+       if (stat(path.c_str(), &st) != 0 && errno == ENOENT)
+               return false;
+       return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gu_mkdir(const string &path)
+{
+#if defined(__linux__) || defined(__APPLE__)
+       if (mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
+#else
+       if (_mkdir(path.c_str()) == 0)
+#endif
+               return true;
+       return false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_basename(const string &s)
+{
+       string out = s;
+       out.erase(0, out.find_last_of(G_SLASH_STR) + 1);
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_dirname(const string &path)
+{
+       if (path.empty())
+               return "";
+       string out = path;
+       out.erase(out.find_last_of(G_SLASH_STR));
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_getCurrentPath()
+{
+ char buf[PATH_MAX];
+#if defined(__WIN32)
+       if (_getcwd(buf, PATH_MAX) != NULL)
+#else
+       if (getcwd(buf, PATH_MAX) != NULL)
+#endif
+               return buf;
+       else
+               return "";
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_getExt(const string &file)
+{
+       // TODO - use std functions
+       int len = strlen(file.c_str());
+       int pos = len;
+       while (pos>0) {
+               if (file[pos] == '.')
+                       break;
+               pos--;
+       }
+       if (pos==0)
+               return "";
+       string out = file;
+       return out.substr(pos+1, len);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_stripExt(const string &s)
+{
+       return s.substr(0, s.find_last_of("."));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gu_isProject(const string &path)
+{
+       /** FIXME - checks too weak */
+
+       if (gu_getExt(path.c_str()) == "gprj" && gu_dirExists(path))
+               return 1;
+       return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_stripFileUrl(const string &f)
+{
+       string out = f;
+       out = gu_replace(out, "file://", "");
+       out = gu_replace(out, "%20", " ");
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_getHomePath()
+{
+       char path[PATH_MAX];
+
+#if   defined(__linux__)
+
+       snprintf(path, PATH_MAX, "%s/.giada", getenv("HOME"));
+
+#elif defined(_WIN32)
+
+       snprintf(path, PATH_MAX, ".");
+
+#elif defined(__APPLE__)
+
+       struct passwd *p = getpwuid(getuid());
+       if (p == NULL) {
+               gu_log("[gu_getHomePath] unable to fetch user infos\n");
+               return "";
+       }
+       else {
+               const char *home = p->pw_dir;
+               snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada", home);
+       }
+
+#endif
+
+       return string(path);
+}
diff --git a/src/utils/fs.h b/src/utils/fs.h
new file mode 100644 (file)
index 0000000..abb9861
--- /dev/null
@@ -0,0 +1,67 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef UTILS_H
+#define UTILS_H
+
+
+#include <string>
+#include <vector>
+
+
+using std::string;
+using std::vector;
+
+
+bool gu_fileExists(const string &path);
+
+bool gu_dirExists(const string &path);
+
+bool gu_isDir(const string &path);
+
+bool gu_isProject(const string &path);
+
+bool gu_mkdir(const string &path);
+
+string gu_getCurrentPath();
+
+string gu_getHomePath();
+
+string gu_basename(const string &s);
+
+string gu_dirname(const string &s);
+
+string gu_getExt(const string &s);
+
+string gu_stripExt(const string &s);
+
+string gu_stripFileUrl(const string &s);
+
+
+#endif
diff --git a/src/utils/gui.cpp b/src/utils/gui.cpp
new file mode 100644 (file)
index 0000000..5daf5d5
--- /dev/null
@@ -0,0 +1,218 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gui_utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include "../core/mixer.h"
+#include "../core/patch_DEPR_.h"
+#include "../core/recorder.h"
+#include "../core/wave.h"
+#include "../core/pluginHost.h"
+#include "../core/channel.h"
+#include "../core/conf.h"
+#include "../core/graphics.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/gd_actionEditor.h"
+#include "../gui/elems/ge_keyboard.h"
+#include "../gui/elems/ge_window.h"
+#include "../gui/elems/channel.h"
+#include "log.h"
+#include "string.h"
+#include "gui.h"
+
+
+extern Mixer          G_Mixer;
+extern unsigned      G_beats;
+extern bool                 G_audio_status;
+extern Patch_DEPR_   G_patch;
+extern Conf          G_conf;
+extern uint32_t      G_time;
+extern gdMainWindow *G_MainWin;
+#ifdef WITH_VST
+extern PluginHost    G_PluginHost;
+#endif
+
+
+static int blinker = 0;
+
+
+void gu_refreshUI()
+{
+       Fl::lock();
+
+       /* update dynamic elements: in and out meters, beat meter and
+        * each channel */
+
+       G_MainWin->inOut->refresh();
+       G_MainWin->beatMeter->redraw();
+       G_MainWin->keyboard->refreshColumns();
+
+       /* compute timer for blinker */
+
+       blinker++;
+       if (blinker > 12)
+               blinker = 0;
+
+       /* redraw GUI */
+
+       Fl::unlock();
+       Fl::awake();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gu_getBlinker()
+{
+       return blinker;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_updateControls()
+{
+       for (unsigned i=0; i<G_Mixer.channels.size(); i++)
+               G_Mixer.channels.at(i)->guiChannel->update();
+
+       G_MainWin->inOut->setOutVol(G_Mixer.outVol);
+       G_MainWin->inOut->setInVol(G_Mixer.inVol);
+#ifdef WITH_VST
+       G_MainWin->inOut->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0);
+       G_MainWin->inOut->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0);
+#endif
+
+       G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
+       G_MainWin->timing->setBpm(G_Mixer.bpm);
+
+       G_MainWin->controller->updatePlay(G_Mixer.running);
+       G_MainWin->controller->updateMetronome(G_Mixer.metronome);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_updateMainWinLabel(const string &s)
+{
+       std::string out = std::string(G_APP_NAME) + " - " + s;
+       G_MainWin->copy_label(out.c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_setFavicon(Fl_Window *w)
+{
+#if defined(__linux__)
+
+       fl_open_display();
+       Pixmap p, mask;
+       XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display),
+               (char **) giada_icon, &p, &mask, NULL);
+       w->icon((char *)p);
+
+#elif defined(_WIN32)
+
+       w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
+
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_openSubWindow(gWindow *parent, gWindow *child, int id)
+{
+       if (parent->hasWindow(id)) {
+               gu_log("[GU] parent has subwindow with id=%d, deleting\n", id);
+               parent->delSubWindow(id);
+       }
+       child->setId(id);
+       parent->addSubWindow(child);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_refreshActionEditor()
+{
+       /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */
+
+       gdActionEditor *aeditor = (gdActionEditor*) G_MainWin->getChild(WID_ACTION_EDITOR);
+       if (aeditor) {
+               Channel *chan = aeditor->chan;
+               G_MainWin->delSubWindow(WID_ACTION_EDITOR);
+               gu_openSubWindow(G_MainWin, new gdActionEditor(chan), WID_ACTION_EDITOR);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gWindow *gu_getSubwindow(gWindow *parent, int id)
+{
+       if (parent->hasWindow(id))
+               return parent->getChild(id);
+       else
+               return NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_closeAllSubwindows()
+{
+       /* don't close WID_FILE_BROWSER, because it's the caller of this
+        * function */
+
+       G_MainWin->delSubWindow(WID_ACTION_EDITOR);
+       G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
+       G_MainWin->delSubWindow(WID_FX_LIST);
+       G_MainWin->delSubWindow(WID_FX);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_removeFltkChars(const string &s)
+{
+       string out = gu_replace(s, "/", "-");
+       out = gu_replace(out, "|", "-");
+       out = gu_replace(out, "&", "-");
+       out = gu_replace(out, "_", "-");
+       return out;
+}
diff --git a/src/utils/gui.h b/src/utils/gui.h
new file mode 100644 (file)
index 0000000..921c9ea
--- /dev/null
@@ -0,0 +1,99 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef GUI_UTILS_H
+#define GUI_UTILS_H
+
+#include <dirent.h>
+#include <string>
+#include <FL/x.H>
+#include <FL/Fl.H>
+#ifdef __APPLE__
+       #include <libgen.h>     // in osx, for basename() (but linux?)
+#endif
+
+/* including stuff for the favicon */
+
+#if defined(_WIN32)
+       #include "../ext/resource.h"
+#elif defined(__linux__)
+       #include <X11/xpm.h>
+#endif
+
+
+using std::string;
+
+
+/* refresh
+ * refresh all GUI elements. */
+
+void gu_refreshUI();
+
+/* getBlinker
+*  return blinker value, used to make widgets blink. */
+
+int gu_getBlinker();
+
+/* updateControls
+ * update attributes of control elements (sample names, volumes, ...).
+ * Useful when loading a new patch. */
+
+void gu_updateControls();
+
+/* update_win_label
+ * update the name of the main window */
+
+void gu_updateMainWinLabel(const string &s);
+
+void gu_setFavicon(Fl_Window *w);
+
+void gu_openSubWindow(class gWindow *parent, gWindow *child, int id);
+
+/* refreshActionEditor
+ * reload the action editor window by closing and reopening it. It's used
+ * when you delete some actions from the mainWindow and the action editor
+ * window is open. */
+
+void gu_refreshActionEditor();
+
+
+/* closeAllSubwindows
+ * close all subwindows attached to mainWin. */
+
+void gu_closeAllSubwindows();
+
+
+/* getSubwindow
+ * return a pointer to an open subwindow, otherwise NULL. */
+
+gWindow *gu_getSubwindow(class gWindow *parent, int id);
+
+/* removeFltkChars
+ * Strip special chars used by FLTK to split menus into sub-menus. */
+
+string gu_removeFltkChars(const string &s);
+
+#endif
diff --git a/src/utils/gui_utils.cpp b/src/utils/gui_utils.cpp
deleted file mode 100644 (file)
index ec711d5..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gui_utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../core/mixer.h"
-#include "../core/patch_DEPR_.h"
-#include "../core/recorder.h"
-#include "../core/wave.h"
-#include "../core/pluginHost.h"
-#include "../core/channel.h"
-#include "../core/conf.h"
-#include "../core/graphics.h"
-#include "../gui/dialogs/gd_warnings.h"
-#include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/dialogs/gd_actionEditor.h"
-#include "../gui/elems/ge_keyboard.h"
-#include "../gui/elems/ge_window.h"
-#include "../gui/elems/ge_channel.h"
-#include "gui_utils.h"
-#include "log.h"
-
-
-extern Mixer          G_Mixer;
-extern unsigned      G_beats;
-extern bool                 G_audio_status;
-extern Patch_DEPR_   G_patch;
-extern Conf          G_conf;
-extern uint32_t      G_time;
-extern gdMainWindow *mainWin;
-#ifdef WITH_VST
-extern PluginHost    G_PluginHost;
-#endif
-
-
-static int blinker = 0;
-
-
-void gu_refresh()
-{
-       Fl::lock();
-
-       /* update dynamic elements: in and out meters, beat meter and
-        * each channel */
-
-       mainWin->inOut->refresh();
-       mainWin->beatMeter->redraw();
-       mainWin->keyboard->refreshColumns();
-
-       /* compute timer for blinker */
-
-       blinker++;
-       if (blinker > 12)
-               blinker = 0;
-
-       /* redraw GUI */
-
-       Fl::unlock();
-       Fl::awake();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gu_getBlinker()
-{
-       return blinker;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_updateControls()
-{
-       for (unsigned i=0; i<G_Mixer.channels.size(); i++) {
-               G_Mixer.channels.at(i)->guiChannel->update();
-       }
-
-       mainWin->inOut->setOutVol(G_Mixer.outVol);
-       mainWin->inOut->setInVol(G_Mixer.inVol);
-#ifdef WITH_VST
-       mainWin->inOut->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0);
-       mainWin->inOut->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0);
-#endif
-
-       mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars);
-       mainWin->timing->setBpm(G_Mixer.bpm);
-
-       /* if you reset to init state while the seq is in play: it's better to
-        * update the button status */
-
-       mainWin->controller->updatePlay(G_Mixer.running);
-       mainWin->controller->updateMetronome(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_update_win_label(const char *c)
-{
-       std::string out = G_APP_NAME;
-       out += " - ";
-       out += c;
-       mainWin->copy_label(out.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_setFavicon(Fl_Window *w)
-{
-#if defined(__linux__)
-       fl_open_display();
-       Pixmap p, mask;
-       XpmCreatePixmapFromData(
-               fl_display,
-               DefaultRootWindow(fl_display),
-               (char **)giada_icon,
-               &p,
-               &mask,
-               NULL);
-       w->icon((char *)p);
-#elif defined(_WIN32)
-       w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
-#endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_openSubWindow(gWindow *parent, gWindow *child, int id)
-{
-       if (parent->hasWindow(id)) {
-               gLog("[GU] parent has subwindow with id=%d, deleting\n", id);
-               parent->delSubWindow(id);
-       }
-       child->setId(id);
-       parent->addSubWindow(child);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_refreshActionEditor()
-{
-       /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */
-
-       gdActionEditor *aeditor = (gdActionEditor*) mainWin->getChild(WID_ACTION_EDITOR);
-       if (aeditor) {
-               Channel *chan = aeditor->chan;
-               mainWin->delSubWindow(WID_ACTION_EDITOR);
-               gu_openSubWindow(mainWin, new gdActionEditor(chan), WID_ACTION_EDITOR);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gWindow *gu_getSubwindow(gWindow *parent, int id)
-{
-       if (parent->hasWindow(id))
-               return parent->getChild(id);
-       else
-               return NULL;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gu_closeAllSubwindows()
-{
-       /* don't close WID_FILE_BROWSER, because it's the caller of this
-        * function */
-
-       mainWin->delSubWindow(WID_ACTION_EDITOR);
-       mainWin->delSubWindow(WID_SAMPLE_EDITOR);
-       mainWin->delSubWindow(WID_FX_LIST);
-       mainWin->delSubWindow(WID_FX);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gu_removeFltkChars(const string &s)
-{
-       string out = gReplace(s, "/", "-");
-       out = gReplace(out, "|", "-");
-       out = gReplace(out, "&", "-");
-       out = gReplace(out, "_", "-");
-       return out;
-}
diff --git a/src/utils/gui_utils.h b/src/utils/gui_utils.h
deleted file mode 100644 (file)
index 605b196..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gui_utils
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-#ifndef GUI_UTILS_H
-#define GUI_UTILS_H
-
-#include <dirent.h>
-#include <string>
-#include <FL/x.H>
-#include <FL/Fl.H>
-#ifdef __APPLE__
-       #include <libgen.h>     // in osx, for basename() (but linux?)
-#endif
-
-/* including stuff for the favicon */
-
-#if defined(_WIN32)
-       #include "../ext/resource.h"
-#elif defined(__linux__)
-       #include <X11/xpm.h>
-#endif
-
-
-using std::string;
-
-
-/* refresh
- * refresh all GUI elements. */
-
-void gu_refresh();
-
-/* getBlinker
-*  return blinker value, used to make widgets blink. */
-
-int gu_getBlinker();
-
-/* updateControls
- * update attributes of control elements (sample names, volumes, ...).
- * Useful when loading a new patch. */
-
-void gu_updateControls();
-
-/* update_win_label
- * update the name of the main window */
-
-void gu_update_win_label(const char *c);
-
-void gu_setFavicon(Fl_Window *w);
-
-void gu_openSubWindow(class gWindow *parent, gWindow *child, int id);
-
-/* refreshActionEditor
- * reload the action editor window by closing and reopening it. It's used
- * when you delete some actions from the mainWindow and the action editor
- * window is open. */
-
-void gu_refreshActionEditor();
-
-
-/* closeAllSubwindows
- * close all subwindows attached to mainWin. */
-
-void gu_closeAllSubwindows();
-
-
-/* getSubwindow
- * return a pointer to an open subwindow, otherwise NULL. */
-
-gWindow *gu_getSubwindow(class gWindow *parent, int id);
-
-/* removeFltkChars
- * Strip special chars used by FLTK to split menus into sub-menus. */
-
-string gu_removeFltkChars(const string &s);
-
-#endif
index 1ebef9fd82cdb65ed977628b1238563fe0e4b7cd..3724f03ee3da80923378999584aab3146a303855 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * log
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include <cstdio>
 #include <cstdarg>
 #include <string>
-#include "../utils/utils.h"
+#include "../utils/fs.h"
 #include "../core/const.h"
 #include "log.h"
 
 
+using std::string;
+
+
 static FILE *f;
 static int   mode;
 static bool  stat;
 
 
-int gLog_init(int m) {
+int gu_logInit(int m)
+{
        mode = m;
        stat = true;
        if (mode == LOG_MODE_FILE) {
-               std::string fpath = gGetHomePath() + "/giada.log";
+               string fpath = gu_getHomePath() + G_SLASH + "giada.log";
                f = fopen(fpath.c_str(), "a");
                if (!f) {
                        stat = false;
@@ -55,19 +59,21 @@ int gLog_init(int m) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void gLog_close() {
+void gu_logClose()
+{
        if (mode == LOG_MODE_FILE)
                fclose(f);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void gLog(const char *format, ...) {
+void gu_log(const char *format, ...)
+{
        if (mode == LOG_MODE_MUTE)
                return;
   va_list args;
index 285a7d6194c5cff23ddeec62eb20db59bf8d62a4..14ece2974c6c126ada1fb644a2fc1b10866ed6a7 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * log
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef __LOG_H__
 /* init
  * init logger. Mode defines where to write the output: LOG_MODE_STDOUT,
  * LOG_MODE_FILE and LOG_MODE_MUTE. */
-int  gLog_init (int mode);
 
-void gLog_close();
+int  gu_logInit(int mode);
 
-void gLog(const char *format, ...);
+void gu_logClose();
+
+void gu_log(const char *format, ...);
 
 
 #endif
index 167ed83e0f1264e29f1ab07cda4d0231a2b5b812..603693e11504b2215a7d2a9afeaeed187ae1c5a5 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include "string.h"
 #include <limits.h>
+#include <sstream>
+#include "string.h"
 
 
 using std::string;
 
 
-string gGetRealPath(const string &path)
+string gu_getRealPath(const string &path)
 {
        string out = "";
 
@@ -54,3 +55,59 @@ string gGetRealPath(const string &path)
        }
        return out;
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_itoa(int i)
+{
+       std::stringstream out;
+       out << i;
+       return out.str();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_trim(const string &s)
+{
+       std::size_t first = s.find_first_not_of(" \n\t");
+       std::size_t last  = s.find_last_not_of(" \n\t");
+       return s.substr(first, last-first+1);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string gu_replace(string in, const string &search, const string &replace)
+{
+       size_t pos = 0;
+       while ((pos = in.find(search, pos)) != string::npos) {
+               in.replace(pos, search.length(), replace);
+               pos += replace.length();
+       }
+       return in;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gu_split(string in, string sep, vector<string> *v)
+{
+       string full  = in;
+       string token = "";
+       size_t curr = 0;
+       size_t next = -1;
+       do {
+         curr  = next + 1;
+         next  = full.find_first_of(sep, curr);
+               token = full.substr(curr, next - curr);
+               if (token != "")
+                       v->push_back(token);
+       }
+       while (next != string::npos);
+}
index 758b74204362ad41f5991745ab5da645b12dabe0..88df1af8bc7a3901e0c09d64796d2398e603bd2f 100644 (file)
 
 
 #include <string>
-#include <cstdio>
 #include <vector>
-#include "log.h"
 
 
 using std::string;
+using std::vector;
 
 
-string gGetRealPath(const string &path);
+string gu_getRealPath(const string &path);
+
+string gu_replace(string in, const string &search, const string &replace);
+
+string gu_trim(const string &s);
+
+string gu_itoa(int i);
+
+void gu_split(string in, string sep, vector<string> *v);
+
 
 #endif
diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp
deleted file mode 100644 (file)
index 16e00f4..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#if defined(_WIN32)                    // getcwd (unix) or __getcwd (win)
-       #include <direct.h>
-       #include <windows.h>
-#else
-       #include <unistd.h>
-#endif
-
-#include <cstdarg>
-#include <sys/stat.h>   // stat (gDirExists)
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string>
-#include <string.h>
-#include <sstream>
-#include <limits.h>
-#if defined(__APPLE__)
-       #include <libgen.h>     // basename unix
-       #include <pwd.h>        // getpwuid
-#endif
-#include "../core/const.h"
-#include "utils.h"
-
-
-using std::string;
-using std::vector;
-
-
-bool gFileExists(const char *filename)
-{
-       FILE *fh = fopen(filename, "rb");
-       if (!fh) {
-               return 0;
-       }
-       else {
-               fclose(fh);
-               return 1;
-       }
-}
-
-
-bool gFileExists(const string &filename)
-{
-       return gFileExists(filename.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsDir(const char *path)
-{
-       bool ret;
-
-#if defined(__linux__)
-
-       struct stat s1;
-       stat(path, &s1);
-       ret = S_ISDIR(s1.st_mode);
-
-#elif defined(__APPLE__)
-
-       if (strcmp(path, "")==0)
-               ret = false;
-       else {
-               struct stat s1;
-               stat(path, &s1);
-               ret = S_ISDIR(s1.st_mode);
-
-               /* check if ret is a bundle, a special OS X folder which must be
-                * shown as a regular file (VST).
-                * FIXME - consider native functions CFBundle... */
-
-               if (ret) {
-                       string tmp = path;
-                       tmp += "/Contents/Info.plist";
-                       if (gFileExists(tmp.c_str()))
-                               ret = false;
-               }
-       }
-
-#elif defined(__WIN32)
-
-  unsigned dwAttrib = GetFileAttributes(path);
-  ret = (dwAttrib != INVALID_FILE_ATTRIBUTES &&
-        (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
-#endif
-
-       return ret & !gIsProject(path);
-}
-
-
-bool gIsDir(const string &path)
-{
-       return gIsDir(path.c_str());
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gDirExists(const char *path)
-{
-       struct stat st;
-       if (stat(path, &st) != 0 && errno == ENOENT)
-               return false;
-       return true;
-}
-
-
-bool gDirExists(const string &path)
-{
-       return gDirExists(path.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gMkdir(const char *path)
-{
-#if defined(__linux__) || defined(__APPLE__)
-       if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0)
-#else
-       if (_mkdir(path) == 0)
-#endif
-               return true;
-       return false;
-}
-
-
-bool gMkdir(const string &path)
-{
-       return gMkdir(path.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gBasename(const string &s)
-{
-       string out = s;
-       out.erase(0, out.find_last_of(G_SLASH_STR) + 1);
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gDirname(const string &path)
-{
-       if (path.empty())
-               return "";
-       string out = path;
-       out.erase(out.find_last_of(G_SLASH_STR));
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gGetCurrentPath()
-{
- char buf[PATH_MAX];
-#if defined(__WIN32)
-       if (_getcwd(buf, PATH_MAX) != NULL)
-#else
-       if (getcwd(buf, PATH_MAX) != NULL)
-#endif
-               return buf;
-       else
-               return "";
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gGetExt(const char *file)
-{
-       int len = strlen(file);
-       int pos = len;
-       while (pos>0) {
-               if (file[pos] == '.')
-                       break;
-               pos--;
-       }
-       if (pos==0)
-               return "";
-       string out = file;
-       return out.substr(pos+1, len);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gStripExt(const char *file)
-{
-       int len = strlen(file);
-       int pos = -1;
-       for (int i=0; i<len; i++)
-               if (file[i] == '.') {
-                       pos = i;
-                       break;
-               }
-       string out = file;
-       return pos == -1 ? out : out.substr(0, pos);
-}
-
-
-string gStripExt(const string &s)
-{
-       return s.substr(0, s.find_last_of("."));
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsProject(const string &path)
-{
-       /** FIXME - checks too weak */
-
-       if (gGetExt(path.c_str()) == "gprj" && gDirExists(path))
-               return 1;
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool gIsPatch(const char *path)
-{
-       if (gGetExt(path) == "gptc")
-               return 1;
-       return 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gGetProjectName(const char *path)
-{
-       string out;
-       out = gStripExt(path);
-
-       int i = out.size();
-       while (i>=0) { /// TODO - use gGetSlash()
-#if defined(__linux__) || defined(__APPLE__)
-               if (out[i] == '/')
-#elif defined(_WIN32)
-               if (out[i] == '\\')
-#endif
-                       break;
-               i--;
-       }
-
-       out.erase(0, i+1);      // includes the '/' (or '\' on windows)
-       return out;
-}
-
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gItoa(int i)
-{
-       std::stringstream out;
-       out << i;
-       return out.str();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gTrim(const char *f)
-{
-       string out = f;
-       return gTrim(out);
-}
-
-
-string gTrim(const string &s)
-{
-       std::size_t first = s.find_first_not_of(" \n\t");
-       std::size_t last  = s.find_last_not_of(" \n\t");
-       return s.substr(first, last-first+1);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gReplace(string in, const string& search, const string& replace)
-{
-       size_t pos = 0;
-       while ((pos = in.find(search, pos)) != string::npos) {
-               in.replace(pos, search.length(), replace);
-               pos += replace.length();
-       }
-       return in;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gStripFileUrl(const char *f)
-{
-       string out = f;
-       out = gReplace(out, "file://", "");
-       out = gReplace(out, "%20", " ");
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string gGetHomePath()
-{
-       char path[PATH_MAX];
-
-#if   defined(__linux__)
-
-       snprintf(path, PATH_MAX, "%s/.giada", getenv("HOME"));
-
-#elif defined(_WIN32)
-
-       snprintf(path, PATH_MAX, ".");
-
-#elif defined(__APPLE__)
-
-       struct passwd *p = getpwuid(getuid());
-       if (p == NULL) {
-               gLog("[gGetHomePath] unable to fetch user infos\n");
-               return "";
-       }
-       else {
-               const char *home = p->pw_dir;
-               snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada", home);
-       }
-
-#endif
-
-       return string(path);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gSplit(string in, string sep, vector<string> *v)
-{
-       string full  = in;
-       string token = "";
-       size_t curr = 0;
-       size_t next = -1;
-       do {
-         curr  = next + 1;
-         next  = full.find_first_of(sep, curr);
-               token = full.substr(curr, next - curr);
-               if (token != "")
-                       v->push_back(token);
-       }
-       while (next != string::npos);
-}
diff --git a/src/utils/utils.h b/src/utils/utils.h
deleted file mode 100644 (file)
index dd6ecd0..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * utils
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef UTILS_H
-#define UTILS_H
-
-
-#include <string>
-#include <cstdio>
-#include <vector>
-#include "log.h"
-
-
-using std::string;
-using std::vector;
-
-
-bool gFileExists(const char *path);
-bool gFileExists(const string &path);
-
-bool gDirExists(const char *path);
-bool gDirExists(const string &path);
-
-bool gIsDir(const char *path);
-bool gIsDir(const string &path);
-
-bool gIsProject(const string &path);
-
-bool gIsPatch(const char *path);
-bool gIsPatch(const string &path);
-
-bool gMkdir(const char *path);
-bool gMkdir(const string &path);
-
-string gBasename(const string &s);
-
-string gReplace(string in, const string& search, const string& replace);
-
-string gDirname(const string &s);
-
-string gTrim(const char *path);
-string gTrim(const string &s);
-
-string gGetCurrentPath();
-
-string gGetHomePath();
-
-string gStripFileUrl(const char *path);
-
-string gGetExt(const char *path);
-
-string gStripExt(const char *path);
-string gStripExt(const string &s);
-
-string gGetProjectName(const char *path); // TODO - useless!
-
-string gItoa(int i);
-
-void gSplit(string in, string sep, vector<string> *v);
-
-#endif
index 8ff99428068d46bcf720dc61cb23c412fbb8bf6f..991ff1f2432fd8c4b4363407eba46453828a27b7 100644 (file)
@@ -69,6 +69,7 @@ TEST_CASE("Test Patch class")
     channel1.midiInKeyPress    = UINT32_MAX;  // check maximum value
     channel1.midiInKeyRel      = 1;
     channel1.midiInKill        = 2;
+    channel1.midiInArm         = 11;
     channel1.midiInVolume      = 3;
     channel1.midiInMute        = 4;
     channel1.midiInSolo        = 5;
@@ -157,6 +158,7 @@ TEST_CASE("Test Patch class")
     REQUIRE(channel0.midiInKeyPress == UINT32_MAX);
     REQUIRE(channel0.midiInKeyRel == 1);
     REQUIRE(channel0.midiInKill == 2);
+    REQUIRE(channel0.midiInArm == 11);
     REQUIRE(channel0.midiInVolume == 3);
     REQUIRE(channel0.midiInMute == 4);
     REQUIRE(channel0.midiInSolo == 5);
index e1f071b0d3d4949cf00eb32abc93132c13784d2d..3ae679c38ff60f9291003372a7e77d25fcdc06ef 100644 (file)
@@ -1,6 +1,8 @@
 #ifdef WITH_VST
 #ifdef RUN_TESTS_WITH_LOCAL_FILES
 
+// temporarily disabled due to entangled deps (WIP)
+#if 0
 
 #include "../src/core/pluginHost.h"
 #include "catch.hpp"
@@ -26,5 +28,7 @@ TEST_CASE("Test PluginHost class")
   }
 }
 
+#endif
+
 #endif
 #endif
index b7c88b3ddfcb19c6c30dc8e93cd176a271fefd9c..0f549205daeace38c989116bed2cf28c134ee5fb 100644 (file)
@@ -1,4 +1,5 @@
-#include "../src/utils/utils.h"
+#include "../src/utils/fs.h"
+#include "../src/utils/string.h"
 #include "catch.hpp"
 
 
@@ -7,27 +8,27 @@ using std::vector;
 
 TEST_CASE("Test filesystem utils")
 {
-  REQUIRE(gFileExists("giada_tests") == true);
-  REQUIRE(gFileExists("ghost_file") == false);
-  REQUIRE(gDirExists("src/") == true);
-  REQUIRE(gDirExists("ghost_dir/") == false);
-  REQUIRE(gIsDir("src/") == true);
-  REQUIRE(gIsDir("giada_tests") == false);
-  REQUIRE(gBasename("tests/utils.cpp") == "utils.cpp");
-  REQUIRE(gDirname("tests/utils.cpp") == "tests");
-  REQUIRE(gGetExt("tests/utils.cpp") == "cpp");
-  REQUIRE(gStripExt("tests/utils.cpp") == "tests/utils");
+  REQUIRE(gu_fileExists("giada_tests") == true);
+  REQUIRE(gu_fileExists("ghost_file") == false);
+  REQUIRE(gu_dirExists("src/") == true);
+  REQUIRE(gu_dirExists("ghost_dir/") == false);
+  REQUIRE(gu_isDir("src/") == true);
+  REQUIRE(gu_isDir("giada_tests") == false);
+  REQUIRE(gu_basename("tests/utils.cpp") == "utils.cpp");
+  REQUIRE(gu_dirname("tests/utils.cpp") == "tests");
+  REQUIRE(gu_getExt("tests/utils.cpp") == "cpp");
+  REQUIRE(gu_stripExt("tests/utils.cpp") == "tests/utils");
 }
 
 
 TEST_CASE("Test string utils")
 {
-  REQUIRE(gReplace("Giada is cool", "cool", "hot") == "Giada is hot");
-  REQUIRE(gTrim("   Giada is cool       ") == "Giada is cool");
-  REQUIRE(gItoa(666) == "666");
+  REQUIRE(gu_replace("Giada is cool", "cool", "hot") == "Giada is hot");
+  REQUIRE(gu_trim("   Giada is cool       ") == "Giada is cool");
+  REQUIRE(gu_itoa(666) == "666");
 
   vector<std::string> v;
-  gSplit("Giada is cool", " ", &v);
+  gu_split("Giada is cool", " ", &v);
   REQUIRE(v.size() == 3);
   REQUIRE(v.at(0) == "Giada");
   REQUIRE(v.at(1) == "is");