New upstream version 0.15.2+ds1
authorIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Sat, 8 Sep 2018 16:20:45 +0000 (18:20 +0200)
committerIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Sat, 8 Sep 2018 16:20:45 +0000 (18:20 +0200)
90 files changed:
ChangeLog
Makefile.am
README.md
src/core/channel.cpp
src/core/channel.h
src/core/conf.cpp
src/core/conf.h
src/core/const.h
src/core/graphics.cpp
src/core/graphics.h
src/core/midiChannel.cpp
src/core/midiChannel.h
src/core/midiDispatcher.cpp
src/core/midiEvent.cpp
src/core/midiEvent.h
src/core/mixer.cpp
src/core/mixer.h
src/core/plugin.cpp
src/core/plugin.h
src/core/range.h [new file with mode: 0644]
src/core/recorder.cpp
src/core/recorder.h
src/core/sampleChannel.cpp
src/core/sampleChannel.h
src/core/sampleChannelProc.cpp
src/core/sampleChannelProc.h
src/core/sampleChannelRec.cpp
src/core/sampleChannelRec.h
src/core/types.h
src/core/wave.cpp
src/core/wave.h
src/ext/giada.ico
src/glue/channel.cpp
src/glue/io.cpp
src/glue/recorder.cpp
src/glue/recorder.h
src/gui/dialogs/about.cpp
src/gui/dialogs/actionEditor/baseActionEditor.cpp [new file with mode: 0644]
src/gui/dialogs/actionEditor/baseActionEditor.h [new file with mode: 0644]
src/gui/dialogs/actionEditor/midiActionEditor.cpp [new file with mode: 0644]
src/gui/dialogs/actionEditor/midiActionEditor.h [new file with mode: 0644]
src/gui/dialogs/actionEditor/sampleActionEditor.cpp [new file with mode: 0644]
src/gui/dialogs/actionEditor/sampleActionEditor.h [new file with mode: 0644]
src/gui/dialogs/gd_actionEditor.cpp [deleted file]
src/gui/dialogs/gd_actionEditor.h [deleted file]
src/gui/dialogs/pluginWindowGUI.cpp
src/gui/elems/actionEditor/action.cpp [deleted file]
src/gui/elems/actionEditor/action.h [deleted file]
src/gui/elems/actionEditor/actionEditor.cpp [deleted file]
src/gui/elems/actionEditor/actionEditor.h [deleted file]
src/gui/elems/actionEditor/baseAction.cpp [new file with mode: 0644]
src/gui/elems/actionEditor/baseAction.h [new file with mode: 0644]
src/gui/elems/actionEditor/baseActionEditor.cpp
src/gui/elems/actionEditor/baseActionEditor.h
src/gui/elems/actionEditor/basePianoItem.cpp [deleted file]
src/gui/elems/actionEditor/basePianoItem.h [deleted file]
src/gui/elems/actionEditor/envelopeEditor.cpp
src/gui/elems/actionEditor/envelopeEditor.h
src/gui/elems/actionEditor/envelopePoint.cpp [new file with mode: 0644]
src/gui/elems/actionEditor/envelopePoint.h [new file with mode: 0644]
src/gui/elems/actionEditor/gridTool.cpp
src/gui/elems/actionEditor/gridTool.h
src/gui/elems/actionEditor/muteEditor.cpp [deleted file]
src/gui/elems/actionEditor/muteEditor.h [deleted file]
src/gui/elems/actionEditor/noteEditor.cpp
src/gui/elems/actionEditor/noteEditor.h
src/gui/elems/actionEditor/pianoItem.cpp
src/gui/elems/actionEditor/pianoItem.h
src/gui/elems/actionEditor/pianoItemOrphaned.cpp [deleted file]
src/gui/elems/actionEditor/pianoItemOrphaned.h [deleted file]
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/actionEditor/pianoRoll.h
src/gui/elems/actionEditor/sampleAction.cpp [new file with mode: 0644]
src/gui/elems/actionEditor/sampleAction.h [new file with mode: 0644]
src/gui/elems/actionEditor/sampleActionEditor.cpp [new file with mode: 0644]
src/gui/elems/actionEditor/sampleActionEditor.h [new file with mode: 0644]
src/gui/elems/actionEditor/velocityEditor.cpp [new file with mode: 0644]
src/gui/elems/actionEditor/velocityEditor.h [new file with mode: 0644]
src/gui/elems/config/tabMidi.cpp
src/gui/elems/config/tabMidi.h
src/gui/elems/mainWindow/keyboard/channelMode.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/utils/cocoa.h
src/utils/cocoa.mm
src/utils/gui.cpp
src/utils/math.cpp
src/utils/math.h
tests/conf.cpp
tests/recorder.cpp

index bc3ffe30c0694204ea49e413111b843b2b648b6b..01eb682ab7c12c0a1a8f59bda9501942488345d8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.15.2 --- 
+- New sample-accurate Action Editor
+- New MIDI Velocity Editor widget
+- Ability to move MIDI events vertically in piano roll (i.e. change note) 
+- Remove mute action recording
+- Better handling of MIDI devices that send NOTEON + velocity 0 as NOTEOFF
+- Avoid calls to deprecated JUCE plug-ins methods
+- Removed useless pthreadGC2.dll from Windows package
+- Can't kill MIDI channels (fix #197)
+- Can't record MIDI actions (fix #202)
+- Fix missing first beat on metronome rendering
+- Fix crash on opening plug-in window on macOS
+
+
 0.15.1 --- 2018 . 07 . 03
 - Deep code refactoring, featuring Channels processors
 - Many new unit tests added
index 2ce25d6ae00b4fa9263644eb0bd31e1960a9ee1e..e101bce87af0baef4cfa7cc2564a99cf7b6a9d3a 100644 (file)
@@ -14,6 +14,7 @@ sourcesMain = src/main.cpp
 sourcesCore =                            \
        src/core/const.h                       \
        src/core/types.h                       \
+       src/core/range.h                       \
        src/core/channel.h                     \
        src/core/channel.cpp                   \
        src/core/sampleChannel.h               \
@@ -112,18 +113,22 @@ sourcesCore =                            \
        src/gui/dialogs/sampleEditor.cpp       \
        src/gui/dialogs/pluginWindowGUI.h      \
        src/gui/dialogs/pluginWindowGUI.cpp    \
-       src/gui/dialogs/gd_actionEditor.h            \
-       src/gui/dialogs/gd_actionEditor.cpp    \
        src/gui/dialogs/pluginChooser.h        \
        src/gui/dialogs/pluginChooser.cpp      \
-       src/gui/dialogs/browser/browserBase.h           \
-       src/gui/dialogs/browser/browserBase.cpp         \
-       src/gui/dialogs/browser/browserDir.h            \
-       src/gui/dialogs/browser/browserDir.cpp          \
-       src/gui/dialogs/browser/browserLoad.h           \
-       src/gui/dialogs/browser/browserLoad.cpp         \
-       src/gui/dialogs/browser/browserSave.h           \
-       src/gui/dialogs/browser/browserSave.cpp         \
+       src/gui/dialogs/actionEditor/baseActionEditor.h     \
+       src/gui/dialogs/actionEditor/baseActionEditor.cpp   \
+       src/gui/dialogs/actionEditor/sampleActionEditor.h   \
+       src/gui/dialogs/actionEditor/sampleActionEditor.cpp \
+       src/gui/dialogs/actionEditor/midiActionEditor.h     \
+       src/gui/dialogs/actionEditor/midiActionEditor.cpp   \
+       src/gui/dialogs/browser/browserBase.h            \
+       src/gui/dialogs/browser/browserBase.cpp          \
+       src/gui/dialogs/browser/browserDir.h             \
+       src/gui/dialogs/browser/browserDir.cpp           \
+       src/gui/dialogs/browser/browserLoad.h            \
+       src/gui/dialogs/browser/browserLoad.cpp          \
+       src/gui/dialogs/browser/browserSave.h            \
+       src/gui/dialogs/browser/browserSave.cpp          \
        src/gui/dialogs/midiIO/midiOutputBase.h          \
        src/gui/dialogs/midiIO/midiOutputBase.cpp        \
        src/gui/dialogs/midiIO/midiOutputSampleCh.h      \
@@ -166,24 +171,24 @@ sourcesCore =                            \
        src/gui/elems/sampleEditor/shiftTool.cpp            \
        src/gui/elems/actionEditor/baseActionEditor.h       \
        src/gui/elems/actionEditor/baseActionEditor.cpp     \
+       src/gui/elems/actionEditor/baseAction.h             \
+       src/gui/elems/actionEditor/baseAction.cpp           \
        src/gui/elems/actionEditor/envelopeEditor.h         \
        src/gui/elems/actionEditor/envelopeEditor.cpp       \
+       src/gui/elems/actionEditor/velocityEditor.h         \
+       src/gui/elems/actionEditor/velocityEditor.cpp       \
+       src/gui/elems/actionEditor/envelopePoint.h          \
+       src/gui/elems/actionEditor/envelopePoint.cpp        \
        src/gui/elems/actionEditor/pianoRoll.h              \
        src/gui/elems/actionEditor/pianoRoll.cpp            \
        src/gui/elems/actionEditor/noteEditor.h                   \
        src/gui/elems/actionEditor/noteEditor.cpp           \
-       src/gui/elems/actionEditor/basePianoItem.h          \
-       src/gui/elems/actionEditor/basePianoItem.cpp        \
        src/gui/elems/actionEditor/pianoItem.h              \
        src/gui/elems/actionEditor/pianoItem.cpp            \
-       src/gui/elems/actionEditor/pianoItemOrphaned.h      \
-       src/gui/elems/actionEditor/pianoItemOrphaned.cpp    \
-       src/gui/elems/actionEditor/muteEditor.h             \
-       src/gui/elems/actionEditor/muteEditor.cpp           \
-       src/gui/elems/actionEditor/actionEditor.h           \
-       src/gui/elems/actionEditor/actionEditor.cpp         \
-       src/gui/elems/actionEditor/action.h                 \
-       src/gui/elems/actionEditor/action.cpp               \
+       src/gui/elems/actionEditor/sampleActionEditor.h           \
+       src/gui/elems/actionEditor/sampleActionEditor.cpp         \
+       src/gui/elems/actionEditor/sampleAction.h                 \
+       src/gui/elems/actionEditor/sampleAction.cpp               \
        src/gui/elems/actionEditor/gridTool.h               \
        src/gui/elems/actionEditor/gridTool.cpp             \
        src/gui/elems/mainWindow/mainIO.h          \
index 1fa51c3f98cbe6d21f25a2000e547719e4ca5119..a5af7a7e50417ca19983b1e21715d8f2fc2aa4a1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -39,23 +39,19 @@ Take a look at the COPYING file for further informations.
 
 ## Documentation
 
-Docs are available online on the official website:
-
-http://www.giadamusic.com/documentation
+Docs are available online on [the official website](https://www.giadamusic.com/documentation-index).
 
 Found a typo or a terrible mistake? Feel free to clone the [website repository](https://github.com/monocasual/giada-www) and send us your pull requests.
 
 ## Build Giada from source
 
-We do our best to make the compilation process as simple as possible. You can find all the information in the [official docs page](http://giadamusic.com/documentation/show/compiling-from-source).
+We do our best to make the compilation process as simple as possible. You can find all the information in the [official docs page](https://www.giadamusic.com/documentation-compiling-from-source).
 
 Something went wrong? Try our new [Docker image](https://github.com/monocasual/giada-docker) for building and running Giada without hurdles. 
 
 ## Bugs, requests and questions for non-developers
 
-Feel free to ask anything on our end-user forum:
-
-http://www.giadamusic.com/forum
+Feel free to ask anything on [our end-user forum](https://www.giadamusic.com/forum).
 
 ## Copyright
 
index 741e1ebea20ff50d9e07eadba42a0fd07d567896..6185d748063a63228e0a7f9b8b0a58d46ffaab08 100644 (file)
@@ -65,7 +65,6 @@ Channel::Channel(ChannelType type, ChannelStatus status, int bufferSize)
        solo           (false),
        volume_i       (1.0f),
        volume_d       (0.0f),
-       mute_i         (false),
        hasActions     (false),
        readActions    (false),
        midiIn         (true),
@@ -98,7 +97,6 @@ void Channel::copy(const Channel* src, pthread_mutex_t* pluginMutex)
        volume_i        = src->volume_i;
        volume_d        = src->volume_d;
        pan             = src->pan;
-       mute_i          = src->mute_i;
        mute            = src->mute;
        solo            = src->solo;
        hasActions      = src->hasActions;
index 904bdb44a569c834b05c4ea8811b8287a463d5f6..a827d54a3a023ce41010ac6caf21479859ff35ed 100644 (file)
@@ -44,9 +44,6 @@
 #endif
 
 
-#undef Status
-
-
 class Plugin;
 class MidiMapConf;
 class geChannel;
@@ -94,7 +91,7 @@ public:
        /* set
        What to do when channel is un/muted. */
 
-       virtual void setMute(bool value, giada::EventType eventType) = 0;
+       virtual void setMute(bool value) = 0;
 
        /* empty
        Frees any associated resources (e.g. waveform for SAMPLE). */
@@ -123,9 +120,8 @@ public:
        virtual bool hasData()        const { return false; };
 
        virtual bool recordStart(bool canQuantize) { return true; };
-       virtual bool recordKill() { return false; };
+       virtual bool recordKill() { return true; };
        virtual void recordStop() {};
-       virtual void recordMute() {};
 
        /* prepareBuffer
        Fill audio buffer with audio data from the internal source. This is actually 
@@ -227,8 +223,6 @@ public:
        
        float volume_i;
        float volume_d;
-
-       bool mute_i;          // internal mute
        
   bool hasActions;      // has something recorded
   bool readActions;     // read what's recorded
index b24b06dfffd91f7a8503a3cdbc6b3afbc3ed4f88..1185eda706465a6c9fc0b6c4cea49277c7a39c3e 100644 (file)
@@ -76,6 +76,9 @@ void sanitize()
        if (actionEditorGridVal < 0 || actionEditorGridVal > G_MAX_GRID_VAL) actionEditorGridVal = 0;
        if (actionEditorGridOn < 0) actionEditorGridOn = 0;
        if (pianoRollH <= 0) pianoRollH = 422;
+       if (sampleActionEditorH <= 0) sampleActionEditorH = 40;
+       if (velocityEditorH <= 0) velocityEditorH = 40;
+       if (envelopeEditorH <= 0) envelopeEditorH = 40;
   if (sampleEditorX < 0) sampleEditorX = 0;
        if (sampleEditorY < 0) sampleEditorY = 0;
        if (sampleEditorW < 500) sampleEditorW = 500;
@@ -162,7 +165,6 @@ int  rsmpQuality    = 0;
 int    midiSystem  = 0;
 int    midiPortOut = G_DEFAULT_MIDI_PORT_OUT;
 int    midiPortIn  = G_DEFAULT_MIDI_PORT_IN;
-bool   noNoteOff   = false;
 string midiMapPath = "";
 string lastFileMap = "";
 int    midiSync    = MIDI_SYNC_NONE;
@@ -226,6 +228,10 @@ int midiInputH = G_DEFAULT_MIDI_INPUT_UI_H;
 int pianoRollY = -1;
 int pianoRollH = 422;
 
+int sampleActionEditorH = 40; 
+int velocityEditorH     = 40; 
+int envelopeEditorH     = 40; 
+
 int pluginListX = 0;
 int pluginListY = 0;
 
@@ -321,7 +327,6 @@ int read()
        if (!storager::setInt(jRoot, CONF_KEY_MIDI_SYSTEM, midiSystem)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MIDI_PORT_OUT, midiPortOut)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MIDI_PORT_IN, midiPortIn)) return 0;
-       if (!storager::setBool(jRoot, CONF_KEY_NO_NOTE_OFF, noNoteOff)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_MIDIMAP_PATH, midiMapPath)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_LAST_MIDIMAP, lastFileMap)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MIDI_SYNC, midiSync)) return 0;
@@ -371,6 +376,9 @@ int read()
        if (!storager::setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_ON, sampleEditorGridOn)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_PIANO_ROLL_Y, pianoRollY)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_PIANO_ROLL_H, pianoRollH)) return 0;
+       if (!storager::setInt(jRoot, CONF_KEY_SAMPLE_ACTION_EDITOR_H, sampleActionEditorH)) return 0;
+       if (!storager::setInt(jRoot, CONF_KEY_VELOCITY_EDITOR_H, velocityEditorH)) return 0;
+       if (!storager::setInt(jRoot, CONF_KEY_ENVELOPE_EDITOR_H, envelopeEditorH)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_PLUGIN_LIST_X, pluginListX)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_PLUGIN_LIST_Y, pluginListY)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_CONFIG_X, configX)) return 0;
@@ -431,7 +439,6 @@ int write()
        json_object_set_new(jRoot, CONF_KEY_MIDI_SYSTEM,               json_integer(midiSystem));
        json_object_set_new(jRoot, CONF_KEY_MIDI_PORT_OUT,             json_integer(midiPortOut));
        json_object_set_new(jRoot, CONF_KEY_MIDI_PORT_IN,              json_integer(midiPortIn));
-       json_object_set_new(jRoot, CONF_KEY_NO_NOTE_OFF,               json_boolean(noNoteOff));
        json_object_set_new(jRoot, CONF_KEY_MIDIMAP_PATH,              json_string(midiMapPath.c_str()));
        json_object_set_new(jRoot, CONF_KEY_LAST_MIDIMAP,              json_string(lastFileMap.c_str()));
        json_object_set_new(jRoot, CONF_KEY_MIDI_SYNC,                 json_integer(midiSync));
@@ -481,6 +488,9 @@ int write()
        json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_ON,     json_integer(sampleEditorGridOn));
        json_object_set_new(jRoot, CONF_KEY_PIANO_ROLL_Y,              json_integer(pianoRollY));
        json_object_set_new(jRoot, CONF_KEY_PIANO_ROLL_H,              json_integer(pianoRollH));
+       json_object_set_new(jRoot, CONF_KEY_SAMPLE_ACTION_EDITOR_H,    json_integer(sampleActionEditorH));
+       json_object_set_new(jRoot, CONF_KEY_VELOCITY_EDITOR_H,         json_integer(velocityEditorH));
+       json_object_set_new(jRoot, CONF_KEY_ENVELOPE_EDITOR_H,         json_integer(envelopeEditorH));
        json_object_set_new(jRoot, CONF_KEY_PLUGIN_LIST_X,             json_integer(pluginListX));
        json_object_set_new(jRoot, CONF_KEY_PLUGIN_LIST_Y,             json_integer(pluginListY));
        json_object_set_new(jRoot, CONF_KEY_CONFIG_X,                  json_integer(configX));
index b881d6de37893be029fed26d271481c9bfa7ac0d..7b9a83bf9e023a3b4718922927a083c281cd6838 100644 (file)
@@ -63,7 +63,6 @@ extern int  rsmpQuality;
 extern int  midiSystem;
 extern int  midiPortOut;
 extern int  midiPortIn;
-extern bool noNoteOff;
 extern std::string midiMapPath;
 extern std::string lastFileMap;
 extern int   midiSync;  // see const.h
@@ -107,6 +106,9 @@ extern int sampleEditorGridOn;
 extern int midiInputX, midiInputY, midiInputW, midiInputH;
 
 extern int pianoRollY, pianoRollH;
+extern int sampleActionEditorH; 
+extern int velocityEditorH; 
+extern int envelopeEditorH; 
 extern int pluginListX, pluginListY;
 extern int configX, configY;
 extern int bpmX, bpmY;
index 6d2e6ba93f1ccba0e5670e6c89bf21995c217bd5..2e244b89e4989410ae7e860e37076c778d88dfa8 100644 (file)
 
 /* -- version --------------------------------------------------------------- */
 #define G_APP_NAME      "Giada"
-#define G_VERSION_STR   "0.15.1"
+#define G_VERSION_STR   "0.15.2"
 #define G_VERSION_MAJOR 0
 #define G_VERSION_MINOR 15
-#define G_VERSION_PATCH 1
+#define G_VERSION_PATCH 2
 
 #define CONF_FILENAME "giada.conf"
 
 #define G_MIN_GUI_WIDTH     816
 #define G_MIN_GUI_HEIGHT    510
 #define G_MAX_IO_CHANS      2
+#define G_MAX_VELOCITY      0x7F
+#define G_MAX_MIDI_CHANS    16
 
 
 
 #define G_DEFAULT_PATCH_NAME       "(default patch)"
 #define G_DEFAULT_MIDI_INPUT_UI_W  300
 #define G_DEFAULT_MIDI_INPUT_UI_H  350
-#define G_DEFAULT_MIDI_ACTION_SIZE 8192   // frames
+#define G_DEFAULT_ACTION_SIZE      8192  // frames
+#define G_DEFAULT_ZOOM_RATIO       128
 
 
 
 #define G_ACTION_KEYPRESS              0x01 // 0000 0001
 #define G_ACTION_KEYREL                        0x02 // 0000 0010
 #define G_ACTION_KILL              0x04 // 0000 0100
-#define G_ACTION_MUTEON                        0x08 // 0000 1000
-#define G_ACTION_MUTEOFF               0x10 // 0001 0000
 #define G_ACTION_VOLUME     0x20 // 0010 0000
 #define G_ACTION_MIDI       0x40 // 0100 0000
 
 #define G_ACTION_KEYS       0x03 // 0000 0011 any key
-#define G_ACTION_MUTES      0x24 // 0001 1000 any mute
 
 #define G_RANGE_CHAR        0x01 // range for MIDI (0-127)
 #define G_RANGE_FLOAT       0x02 // range for volumes and VST params (0.0-1.0)
@@ -280,7 +280,7 @@ it drives knobs, volume, faders and such. */
 #define MIDI_CHAN_14        0x0E << 24
 #define MIDI_CHAN_15        0x0F << 24
 
-const int MIDI_CHANS[16] = {
+const int MIDI_CHANS[G_MAX_MIDI_CHANS] = {
        MIDI_CHAN_0,  MIDI_CHAN_1,      MIDI_CHAN_2,  MIDI_CHAN_3,
        MIDI_CHAN_4,  MIDI_CHAN_5,      MIDI_CHAN_6,  MIDI_CHAN_7,
        MIDI_CHAN_8,  MIDI_CHAN_9,      MIDI_CHAN_10, MIDI_CHAN_11,
@@ -384,7 +384,6 @@ const int MIDI_CHANS[16] = {
 #define CONF_KEY_MIDI_SYSTEM              "midi_system"
 #define CONF_KEY_MIDI_PORT_OUT            "midi_port_out"
 #define CONF_KEY_MIDI_PORT_IN             "midi_port_in"
-#define CONF_KEY_NO_NOTE_OFF              "no_note_off"
 #define CONF_KEY_MIDIMAP_PATH             "midimap_path"
 #define CONF_KEY_LAST_MIDIMAP             "last_midimap"
 #define CONF_KEY_MIDI_SYNC                "midi_sync"
@@ -434,6 +433,9 @@ const int MIDI_CHANS[16] = {
 #define CONF_KEY_SAMPLE_EDITOR_GRID_ON    "sample_editor_grid_on"
 #define CONF_KEY_PIANO_ROLL_Y             "piano_roll_y"
 #define CONF_KEY_PIANO_ROLL_H             "piano_roll_h"
+#define CONF_KEY_SAMPLE_ACTION_EDITOR_H   "sample_action_editor_h"
+#define CONF_KEY_VELOCITY_EDITOR_H        "velocity_editor_h"
+#define CONF_KEY_ENVELOPE_EDITOR_H        "envelope_editor_h"
 #define CONF_KEY_PLUGIN_LIST_X            "plugin_list_x"
 #define CONF_KEY_PLUGIN_LIST_Y            "plugin_list_y"
 #define CONF_KEY_CONFIG_X                 "config_x"
index c6be10f20bc2547b3001313fe841e12e1d9bf36b..b73474b02cde5e6ba7bd946a8b27d07dcf1f2f10 100644 (file)
 
 #include "graphics.h"
 
-const char *giada_logo_xpm[] = {
-"300 82 8 1",
-"      c #181917",
-".     c #333432",
-"+     c #484A47",
-"@     c #5F615E",
-"#     c #767875",
-"$     c #8D8F8C",
-"%     c #A5A7A4",
-"&     c #C5C7C4",
-"                                                                                                                                                          .#%%&$                                                                                                                                            ",
-"                                                                                                                                                      ..#%&&&&&#                                                                                                                                            ",
-"                                                                                                                                                 +@#$%&&&&&&&&&@                                                                                                                                            ",
-"                                                              ..                                                                                +&&&&&&&&&&&&&&.                                                                                                                                            ",
-"                                                            +$%%#+                                                                              +%&&&&&&&&&&&&&.                                                                                                                                            ",
-"                                                           #&&&&&%+                                                                             .+@@$&&&&&&&&&%.                                                                                                                                            ",
-"                                                          #&&&&&&&$                                                                                  +&&&&&&&&#                                                                                                                                             ",
-"                                                         .&&&&&&&&%.                                                                                  #&&&&&&&@                                                                                                                                             ",
-"                                                         @&&&&&&&&$                                                                                   +&&&&&&&+                                                                                                                                             ",
-"                                                         $&&&&&&&&#                                                                                   .&&&&&&&.                                                                                                                                             ",
-"                                                         #&&&&&&&&.                                                                                   +&&&&&&%.                                                                                                                                             ",
-"                                                         .&&&&&&&@                                                                                    @&&&&&&$.                                                                                                                                             ",
-"                                                          @&&&&&@                                                                                     $&&&&&&#                                                                                                                                              ",
-"                                                           .##@.                                                                                      %&&&&&&@                                                                                                                                              ",
-"                                                                                                                                                      &&&&&&&+                                                                                                                                              ",
-"                                                                                                                                                     .&&&&&&%.                                                                                                                                              ",
-"                                                                                                                                                     @&&&&&&$.                                                                                                                                              ",
-"                     .+@@###@+.        ......               ...                      ++@@###@@.       .......                      .+@@###@@+.       #&&&&&&#                       .+@@###@@+        .......                                                                                               ",
-"                  .@$%%&&&&&&&%$+     +%%%%%%.         .+@#$%%$.                  .@$%&&&&&&&&%$@.    $%%%%%%+                  .@#%%&&&&&&&&%$@     %&&&&&&@                    .@$%%&&&&&&&%$#.    @%%%%%%@                                                                                               ",
-"                 #%&&&&&&&&&&&&&&$.   #&&&&&&    +@#$$%%%&&&&&%.                .$%&&&&&&&&&&&&&&%@  .&&&&&&&+                 #%&&&&&&&&&&&&&&&$+   &&&&&&&@                   #%&&&&&&&&&&&&&&%#.  %&&&&&&@                                                                                               ",
-"               +%&&&&&&&&&&&&&&&&&%@ .&&&&&&%   .%&&&&&&&&&&&&$                #%&&&&&&&&&&&&&&&&&&$ +&&&&&&%.               @%&&&&&&&&&&&&&&&&&&&# .&&&&&&%+                 @%&&&&&&&&&&&&&&&&&&%. &&&&&&&+                                                                                               ",
-"              #&&&&&&&&&#+....@$&&&&@@&&&&&&$   .&&&&&&&&&&&&&#              +%&&&&&&&&%#+....+#%&&&$#&&&&&&$.             .$&&&&&&&&&$+.....@%&&&&$@&&&&&&%.               .$&&&&&&&&&#@.....#%&&&%+&&&&&&%.                                                                                               ",
-"             $&&&&&&&&@         .%&&&&&&&&&&@    .@$&&&&&&&&&&@             +%&&&&&&&%@         .#&&&&&&&&&&$             .%&&&&&&&&@          .$&&&&&&&&&&$               .%&&&&&&&&#.         @&&&&&&&&&&%.                                                                                               ",
-"            $&&&&&&&%.            @&&&&&&&&&+       .%&&&&&&&%+            @&&&&&&&&#             +%&&&&&&&&#            +%&&&&&&&$.             @&&&&&&&&&#              .%&&&&&&&$.            .%&&&&&&&&$                                                                                                ",
-"           %&&&&&&&#               @&&&&&&&&.        +%&&&&&&%.           @&&&&&&&&#               .%&&&&&&&@           +%&&&&&&&#                @&&&&&&&&@             +%&&&&&&&#                %&&&&&&&@                                                                                                ",
-"          $&&&&&&&$                 #&&&&&&%.         %&&&&&&%           +&&&&&&&&@                 +&&&&&&%+          .%&&&&&&&#                  @&&&&&&&+            .%&&&&&&&#                  &&&&&&&+                                                                                                ",
-"         @&&&&&&&$.                 #&&&&&&$          %&&&&&&$          .%&&&&&&&@                  @&&&&&&%.         .$&&&&&&&$                   +&&&&&&%+            $&&&&&&&$                  .&&&&&&&+                                                                                                ",
-"        +&&&&&&&%+                  %&&&&&&#          %&&&&&&#          $&&&&&&&$                   $&&&&&&%          @&&&&&&&%                    #&&&&&&%.           #&&&&&&&%.                  @&&&&&&%.                                                                                                ",
-"        %&&&&&&&#                   &&&&&&&+         .%&&&&&&@         @&&&&&&&$                    %&&&&&&$         +&&&&&&&&+                    $&&&&&&$           +&&&&&&&%.                   $&&&&&&$.                                                                                                ",
-"       @&&&&&&&%.                  .&&&&&&&.         +%&&&&&%.        .&&&&&&&&.                   .%&&&&&&#         $&&&&&&&#                     %&&&&&&#          .$&&&&&&&@                    %&&&&&&#                                                                                                 ",
-"      .%&&&&&&&@                   @&&&&&&&.         @&&&&&&%         @&&&&&&&#                    @&&&&&&&+        +&&&&&&&&.                    +&&&&&&&@          +&&&&&&&%                    .&&&&&&&@                                                                                                 ",
-"      @&&&&&&&%                    $&&&&&&%.         #&&&&&&%         &&&&&&&&.                    #&&&&&&%.        %&&&&&&&#                     @&&&&&&%+         .$&&&&&&&@                    +&&&&&&&+                                                                                                 ",
-"     .$&&&&&&&#                    %&&&&&&#          $&&&&&&#        #&&&&&&&#                     $&&&&&&%        +&&&&&&&&.                     $&&&&&&%.         +&&&&&&&%                     #&&&&&&%+                                                                                                 ",
-"     +%&&&&&&&+                   .&&&&&&&@         .%&&&&&&@        %&&&&&&&+                    .%&&&&&&$        $&&&&&&&$                      %&&&&&&%          #&&&&&&&#                     %&&&&&&%.                                                                                                 ",
-"     @&&&&&&&%                    +&&&&&&&+         +%&&&&&&+       .&&&&&&&%.                    +&&&&&&&#        &&&&&&&&+                     +%&&&&&&$         .%&&&&&&&.                     &&&&&&&$                                                                                                  ",
-"     $&&&&&&&@                    #&&&&&&&.         @&&&&&&&.       #&&&&&&&#                     #&&&&&&&@       +&&&&&&&%.                     @&&&&&&&#         .&&&&&&&%                     +&&&&&&&#                                                                                                  ",
-"    .%&&&&&&&.                    %&&&&&&%.         #&&&&&&%        %&&&&&&&+                     $&&&&&&&+       #&&&&&&&$.                     $&&&&&&&+         @&&&&&&&@                     #&&&&&&&@                                                                                                  ",
-"    +&&&&&&&&                     &&&&&&&$.         #&&&&&&$        &&&&&&&%.                    .%&&&&&&&        %&&&&&&&#                     .%&&&&&&%.         $&&&&&&&+                     $&&&&&&%+                                                                                                  ",
-"    +&&&&&&&$                    +&&&&&&&#         .$&&&&&&#       .&&&&&&&$.                    +&&&&&&&%        %&&&&&&&+                     +%&&&&&&%          %&&&&&&&.                    .%&&&&&&%.                                                                                                  ",
-"    @&&&&&&&@                    $&&&&&&&@         .%&&&&&&+       +&&&&&&&#                     #&&&&&&&$        &&&&&&&&+                     #&&&&&&&%          &&&&&&&%                     @&&&&&&&$                                                                                                   ",
-"    @&&&&&&&+                    &&&&&&&&+         +%&&&&&&.       @&&&&&&&@                    .%&&&&&&&@       .&&&&&&&%.                    .%&&&&&&&#          &&&&&&&#                     $&&&&&&&$                                                                                                   ",
-"    #&&&&&&&.                   @&&&&&&&%.         @&&&&&&&        @&&&&&&&@                    @&&&&&&&&+       .&&&&&&&%.                    @&&&&&&&&@         .&&&&&&&#                    +%&&&&&&&#                                                                                                   ",
-"    #&&&&&&&.                   %&&&&&&&$.         #&&&&&&%        #&&&&&&&+                   .$&&&&&&&&.       .&&&&&&&$.                   .$&&&&&&&&.         .&&&&&&&@                    $&&&&&&&&@                                                                                                   ",
-"    #&&&&&&&                   #&&&&&&&&$          $&&&&&&#        @&&&&&&&+                   @&&&&&&&&&        .&&&&&&&$.                   @&&&&&&&&&          .&&&&&&&+                   +%&&&&&&&%+                                                                                                   ",
-"    @&&&&&&&                  .%&&&&&&&&#         .%&&&&&&@        @&&&&&&%+                  .%&&&&&&&&%         &&&&&&&$.                  .%&&&&&&&&%           &&&&&&&+                   $&&&&&&&&%.                                                                                                   ",
-"    @&&&&&&&.                 $&&&&&&&&&@         +%&&&&&&.        +&&&&&&&@                  @&&&&&&&&&$         &&&&&&&%.                  #&&&&&&&&&$           &&&&&&&@                  +&&&&&&&&&%                                                                                                    ",
-"    +&&&&&&&+                @&&&&&&&&&%+         +&&&&&&&          &&&&&&&@                 +&&&&&&&&&&#         $&&&&&&%+                 @&&&&&&&&&&#           $&&&&&&#                 .%&&&&&&&&&%                                                                                                    ",
-"    .%&&&&&&@               +%&&$&&&&&&%.         +&&&&&&&          %&&&&&&#                .&&&&&&&&&&&@         @&&&&&&&+                +&&&$%&&&&&&@           @&&&&&&$                .$&&&&&&&&&&$                                                                                                    ",
-"     #&&&&&&$              .$&&##&&&&&&$          @&&&&&&&          @&&&&&&%.              .%&&%@%&&&&&&@         .&&&&&&&#               .&&&$+%&&&&&&.           .&&&&&&&.              .#&&%@%&&&&&&$                                                                                                    ",
-"     +&&&&&&&.            .%&&% $&&&&&&#          +&&&&&&&.        +.&&&&&&&@             .%&&%+.%&&&&&&$        @+$&&&&&&&+             +&&&% +&&&&&&&+        .+  $&&&&&&$             .$&&&@ %&&&&&&%        .#                                                                                          ",
-"      $&&&&&&$           +%&&&+ %&&&&&&@          +&&&&&&&@       #&$#&&&&&&%+           @&&&&@ .$&&&&&&&+      #&&@&&&&&&&$.          .#&&&%. +%&&&&&&#       .$&$ +&&&&&&&+           +%&&&#  $&&&&&&&#      +&&$                                                                                         ",
-"      +%&&&&&&#.       +#&&&%@ .%&&&&&&+          .%&&&&&&&+    .$&&%.%&&&&&&%+        +#&&&&@   #&&&&&&&%@..+@$&&&+@&&&&&&&%+       .@%&&&%+  .%&&&&&&&+     +%&&$. #&&&&&&%@        +#&&&&#   @&&&&&&&&@...+#&&&#                                                                                         ",
-"       @&&&&&&&$@+..++#%&&&%+  +&&&&&&%.           $&&&&&&&%#@@#%&&%. .%&&&&&&%@+...+@$&&&&%+    +%&&&&&&&&%$%&&&&+  $&&&&&&&&$#@+@@#%&&&&$.    #&&&&&&&&#@+@$&&&$.  .$&&&&&&&#+...++#%&&&&@    .%&&&&&&&&%$%&&&&#                                                                                          ",
-"        @&&&&&&&&%%%%&&&&&$.   @&&&&&&%            +%&&&&&&&&&&&&&$.   +%&&&&&&&&%$%%&&&&&$.      #&&&&&&&&&&&&&%+   .$&&&&&&&&&&&&&&&&&&#      .%&&&&&&&&&&&&&&#     .$&&&&&&&&%$%%&&&&&%+      @&&&&&&&&&&&&&%@                                                                                           ",
-"         @%&&&&&&&&&&&&&%@.    #&&&&&&$             #&&&&&&&&&&&%@.     .$&&&&&&&&&&&&&&%@.       .%&&&&&&&&&&&#.      @&&&&&&&&&&&&&&&$+        +&&&&&&&&&&&&%+       .#&&&&&&&&&&&&&&&#.        $&&&&&&&&&&&$+                                                                                            ",
-"          .#%&&&&&&&&&%+.      %&&&&&&#              +%&&&&&&&%#.         +$&&&&&&&&&&%@.          .$&&&&&&&&#+         .#&&&&&&&&&&%#.           .$&&&&&&&&%@.          +$&&&&&&&&&&%@.          .@&&&&&&&&$+.                                                                                             ",
-"            .+#$%%$#+..       .%&&&&&&+               .@#$%$#+.             .@#$%%$#@+               +@$%$#+.             .+#$%%$#@+.               +@$%$$@.               .+#$%%$#@+.              .@$%$#@.                                                                                                ",
-"                              +&&&&&&%.                                                                                                                                                                                                                                                                     ",
-"                              #&&&&&&%                                                                                                                                                                                                                                                                      ",
-"                             .%&&&&&&@                                                                                                                                                                                                                                                                      ",
-"                             @&&&&&&%.                                                                                                                                                                                                                                                                      ",
-"                             $&&&&&&$                                                                                                                                                                                                                                                                       ",
-"                            @&&&&&&&+                                                                                                                                                                                                                                                                       ",
-"  @#$#+                    .$&&&&&&$                                                                                                                                                                                                                                                                        ",
-" $&&&&&#                   #&&&&&&%                                                                                                                                                                                                                                                                         ",
-"#&&&&&&&@                 @&&&&&&&+                                                                                                                                                                                                                                                                         ",
-"%&&&&&&&%.               @&&&&&&%+                                                                                                                                                                                                                                                                          ",
-"%&&&&&&&&#              #&&&&&&%.                                                                                                                                                                                                                                                                           ",
-"@&&&&&&&&&@           .$&&&&&&#.                                                                                                                                                                                                                                                                            ",
-" $&&&&&&&&&$+       +$&&&&&&%+                                                                                                                                                                                                                                                                              ",
-"  +&&&&&&&&&&%#@@#$%&&&&&&&#.                      +.     .+    +@.     ++    .+   +++++          +.    .+     ++     +++++.    .++++.        +@.       .@+     .++++.    .+++++++       +.         +@.       .+@.    .++++.         ++.      ++.    .+.      .+@.    .+     +.  .+  .+.    .+  .+++++++    ",
-"   .$&&&&&&&&&&&&&&&&&&&%@                         $%.    %@  +&&%&%.  .$$    +&  .&&&&&&#       .%@    +&.    %&+    $&&&&&%.  @&&&&&%.    +&&%&%.   .%&%&&+   #&&&&&&@  +&&&&&&%.      &#       +&&%&%.    @&&%&%.  +&&&&&&@       $&%     +%&+   .$&@     @&&%&$.  $%    .%$  $%  +&%.   +%. +&&&&&&$.   ",
-"      +$%%&&&&&&&&&&%$@.                           +&#   #%  +&#   %%   $$    +&  .&+   @&@      .%@    +&.   +$&$    $$   .%%  @%   .%&.  .&$  .%$.  %%.  #&+  #&   .$&+ +&.            &#      +&#   $%.  @&#  .%%. +&.   $&+      $%&+    #%&+   .&%$    @&#  +%$  $%    .%#  $%  +&%$   +%. +&.         ",
-"         .++@###@@+.                                #&. .&+  $%.   .&@  $$    +&  .&+    %$      .%@    +&.   ##$%    $$    @&. @%     %$  $%.   @&. @&+    %$. #&    .%@ +&.            &#      %%    .&#  %%    .&@ +&.    &#      $#%$    $#&+   @%@%.   %%    @%+ $%    .%#  $%  +&+%+  +%. +&.         ",
-"                                                    .%$ $$  .&#     %%  $$    +&  .&+    %$      .%@    +&.  .%@+&+   $$    @&. @%     #&  &#     +. %%     #&. #&    .%@ +&.            &#     .&@     $$ +&+    .$$ +&.    %#      $#@&   +$@&+   $#.%@  +&@    .+. $%    .%#  $%  +& $$  +%. +&.         ",
-"                                                     @&#&.  .&@     $&  $$    +&  .&#+++#&+      .%%####$&.  +%. %$   $%.++@&$  @%     +&..&@        &$     @&+ #&++++$%. +&$###@        &#     +&+     #%.@&.     #% +&+ ..#&+      $#.&@  ##+&+  .&..$$  @&.        $&$###$&#  $%  +& +%@ +%. +&####+     ",
-"                                                      %&@   +&+     #&  $$    +&  .&%$$%%@       .%%####$&.  #$  #&   $&$$%&#.  @%     +&++&@        &#     +&+ #&$$%&%+  +&$$$$#        &#     @&.     #%.@&.     #%.+%%%%%%@       $# $% .$+.&+  @%  @%. @&.        $&$###$&#  $%  +&  #%.+%. +&$$$$@     ",
-"                                                      #&.   .&@     $%  $$    +&  .&#+.$%.       .%@    +&. .$%##$&+  $%.+@&@   @%     +&..&@        &$     @&. #&+++$$   +&+            &#     +&.     #% @&.     $$ +&#@@++        $# +&.+$.+&+  $%@#$&+ @&.        $%    .%#  $%  +&  .%@+%. +&.         ",
-"                                                      @&    .%#     &$  $$    +%  .&+  .%@       .%@    +&. +%$###&$  $$   $%   @%     $&  &$    .$+ $%     #%. #&   +&+  +&.            &#     .&@    .%$ +&@    .%# +&.            $# .%### +&+ .&####&# .&@    .$+ $%    .%#  $%  +&   @%@%. +&.         ",
-"                                                      @&     #%.   @&.  #%.   $%  .&+   $%       .%@    +&. @$.   #&  $$   +&+  @%    +&@  #&.   #&. +&+   .%@  #&   .%#  +&.            &#      $%    +&+  %%    @&+ +&.            $#  #&%+ +&+ @%    #%. %%    #%. $%    .%#  $%  +&   .$%%. +&.         ",
-"                                                      @&     .%%+.@&#   .%%++#&@  .&+   +&+      .%@    +&. $#    .&+ $$    %$  @&+++#&%.   $%+.#&#   #&@.+%%.  #&    @%. +&@+++++.      &$++++. .%%+.@%#   .%%..@&#  +&.            $#  +&$  +&+ %#    +&+ .%%+.#&#  $%    .%#  $%  +&    +&&. +&@++++.  %&",
-"                                                      @&      .$&&%@     +%&&&@   .&+    %$      .%@    +&..%+     %$ $$    @&. @&&&&%@     .$%&&#     @%&&$.   #&    .%@ +&&&&&&%+      &&&&&&$. .$&&%#     .$&&%@   +&.            $#  .%#  +&+.&.    .%#  .$&&&@   $%    .%#  $%  +&     $&. +&&&&&&%. &&"};
-
-
-const char *loopRepeat_xpm[] = {
+const char* giada_logo_xpm[] = {
+"245 86 12 1",
+"      c #191919",
+".     c #303030",
+"+     c #404040",
+"@     c #454545",
+"#     c #5A5A5A",
+"$     c #686868",
+"%     c #818181",
+"&     c #9C9C9C",
+"*     c #B8B8B8",
+"=     c #CDCDCD",
+"-     c #DDDDDD",
+";     c #FEFEFE",
+"                                   ...+++@@@@++...                                                                                                                                                                                                   ",
+"                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
+"                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
+"                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
+"                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
+"                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
+"                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
+"                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
+"                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
+"                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
+"               @@@@@@@@@@@@@@@@@@++$*--;;;;;;;;-=&@+@@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
+"             .@@@@@@@@@@@@@@@@+#&=;;;;;;;;;;;;;;;;;-*%++@@@@@@@@@@@@@@@+                                                                                                                                                                             ",
+"            .@@@@@@@@@@@@@@@@$=;;;;;;;;;;;;;;;;;;;;;;;;&#+@@@@@@@@@@@@@@@                                                                                                                                                                            ",
+"           .@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@                                                                                                                                                                           ",
+"           @@@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@+                                                                                                                                                                          ",
+"          @@@@@@@@@@@@@+*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@+                                                                                                                                                                         ",
+"         @@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@.                                                                                                                                                                        ",
+"        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@@@                                                                                                                                                                        ",
+"       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@@@                                                                                                                                                                       ",
+"       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@@.                                                                                                                                                                      ",
+"      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@                                                                                                                                                                      ",
+"      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@+                                                                                                                                                                     ",
+"     @@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@.                                                                                                                                                                    ",
+"    .@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;=*&%%%%&*-;;;;;;;;;;;;;;;;;;;;;%+@@@@@@@@@@                                                                                                                                                                    ",
+"    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;-%++@@@@@@@++@*-;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@.                                                                                                                                                                   ",
+"   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;=+@@@@@@@@@@                                                                                                                                                                   ",
+"   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-$+@@@@@@@@@@@@@@@@@@@&;;;;;;;;;;;;;;;;;%@@@@@@@@@@.                        %*------=*%.              $%%%%%%%                $%%%%%%%%.               #%%%%%%%%%%%%%%$@                         %%%%%%%%%            ",
+"   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@+$;;;;;;;;;;;;;;;;-+@@@@@@@@@+                     #=;;;;;;;;;;;;;=$           .;;;;;;;;&              &;;;;;;;;;;               ;;;;;;;;;;;;;;;;;;-&#                    -;;;;;;;;;=           ",
+"  .@@@@@@@@@@;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;%@@@@@@@@@@                   .=;;;;;;;;;;;;;;;;;;#         +;;;;;;;;*              ;;;;;;;;;;;&             .;;;;;;;;;;;;;;;;;;;;;;@                 .;;;;;;;;;;;.          ",
+"  +@@@@@@@@@%;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;@@@@@@@@@@.                 @;;;;;;;;;;;;;;;;;;;;;*        +;;;;;;;;*             +;;;;;;;;;;;;             .;;;;;;;;;;;;;;;;;;;;;;;*                &;;;;;;;;;;;*          ",
+"  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;$@@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;=       +;;;;;;;;*             *;;;;;;;;;;;;.            .;;;;;;;;;;;;;;;;;;;;;;;;=               ;;;;;;;;;;;;;          ",
+" .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;=+@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;&      +;;;;;;;;*            .;;;;;;;;;;;;;&            .;;;;;;;;;;;;;;;;;;;;;;;;;*             #;;;;;;;;;;;;;+         ",
+" +@@@@@@@@@&;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@               *;;;;;;;;;;;;;;;;;;;;;;;;;;#     +;;;;;;;;*            $;;;;;;;;;;;;;;            .;;;;;;;;;;;;;;;;;;;;;;;;;;#            *;;;;;;;;;;;;;=         ",
+" @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+#*;;;-&@@@@@@@@@@@@@@;;;;;;;;;;;;;;%@@@@@@@@@.             +;;;;;;;;;;-#   #-;;;;;;;;;;=     +;;;;;;;;*            =;;;;;;;;;;;;;;#           .;;;;;;;;-&&&&*-;;;;;;;;;;;;            ;;;;;;;;;;;;;;;.        ",
+" @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*+@@@@@@@@@@+&;;;;;;;;;;;;;*+@@@@@@@@+             &;;;;;;;;;%       %;;;;;;;;;;     +;;;;;;;;*           .;;;;;;;;;;;;;;;*           .;;;;;;;;=       #;;;;;;;;;;#          %;;;;;;;;;;;;;;;$        ",
+".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+&;;;;;;;;;;;;#@@@@@@@@@@#;;;;;;;;;;;;;;+@@@@@@@@@             =;;;;;;;;=         =;;;;;;;;;@    +;;;;;;;;*           &;;;;;;;%;;;;;;;;           .;;;;;;;;=         ;;;;;;;;;&          -;;;;;;;%;;;;;;;=        ",
+".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@@-;;;;;;;;;;;;;#@@@@@@@@@             ;;;;;;;;;@          -;;;;;;;;.    +;;;;;;;;*           -;;;;;;;+*;;;;;;;%          .;;;;;;;;=         %;;;;;;;;-          ;;;;;;;; ;;;;;;;;.       ",
+".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;%@@@@@@@@@             ;;;;;;;;;                         +;;;;;;;;*          .;;;;;;;; #;;;;;;;=          .;;;;;;;;=          ;;;;;;;;;         &;;;;;;;& &;;;;;;;&       ",
+"+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@            .;;;;;;;;-                         +;;;;;;;;*          *;;;;;;;%  ;;;;;;;;          .;;;;;;;;=          -;;;;;;;;         ;;;;;;;;. @;;;;;;;-       ",
+"+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;-+@@@@@@@@+-;;;;;;;;;;;;*@@@@@@@@@.           .;;;;;;;;-                         +;;;;;;;;*          ;;;;;;;;.  *;;;;;;;&         .;;;;;;;;=          =;;;;;;;;.       .;;;;;;;;   ;;;;;;;;.      ",
+"+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@-;;;;;;;;;;;;=@@@@@@@@@.           .;;;;;;;;-      .%%%%%%%%%%%%$     +;;;;;;;;*         +;;;;;;;-   .;;;;;;;;         .;;;;;;;;=          =;;;;;;;;.       &;;;;;;;*   %;;;;;;;*      ",
+"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;%    +;;;;;;;;*         *;;;;;;;&    ;;;;;;;;.        .;;;;;;;;=          *;;;;;;;;.       ;;;;;;;;.   .;;;;;;;;      ",
+"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        .;;;;;;;;     *;;;;;;;&        .;;;;;;;;=          *;;;;;;;;+      #;;;;;;;-     ;;;;;;;;+     ",
+"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@#$$&*-;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        $;;;;;;;=     .;;;;;;;;        .;;;;;;;;=          *;;;;;;;;+      *;;;;;;;&     %;;;;;;;*     ",
+"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@+@=;;;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        =;;;;;;;%      -;;;;;;;#       .;;;;;;;;=          *;;;;;;;;.      ;;;;;;;;+      ;;;;;;;;.    ",
+"+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@@@@@@#-;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*       .;;;;;;;;.      &;;;;;;;*       .;;;;;;;;=          =;;;;;;;;.     %;;;;;;;-       =;;;;;;;#    ",
+"+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;;+@@@@@+++++++@@@@@@@&;;*@@@@@@@@@.           .;;;;;;;;-      @%%%%*;;;;;;;;&    +;;;;;;;;*       &;;;;;;;=.......#;;;;;;;;       .;;;;;;;;=          =;;;;;;;;.     -;;;;;;;%.......&;;;;;;;=    ",
+"+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@+#%*-;;-=&$@@@@@@@%;&@@@@@@@@@             ;;;;;;;;;           %;;;;;;;;%    +;;;;;;;;*       -;;;;;;;;;;;;;;;;;;;;;;;;%      .;;;;;;;;=          -;;;;;;;;      ;;;;;;;;;;;;;;;;;;;;;;;;;.   ",
+".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@*;;;;;;;;;;;%@@@@@@&%@@@@@@@@@             ;;;;;;;;;           &;;;;;;;;%    +;;;;;;;;*       ;;;;;;;;;;;;;;;;;;;;;;;;;=      .;;;;;;;;=          ;;;;;;;;;     %;;;;;;;;;;;;;;;;;;;;;;;;;&   ",
+".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@+%;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@             -;;;;;;;;#          =;;;;;;;;@    +;;;;;;;;*      *;;;;;;;;;;;;;;;;;;;;;;;;;;      .;;;;;;;;=         $;;;;;;;;-     ;;;;;;;;;;;;;;;;;;;;;;;;;;-   ",
+".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+*;;;;;;;;;;;;#@+*;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@@             =;;;;;;;;=         @;;;;;;;;;     +;;;;;;;;*      ;;;;;;;;;;;;;;;;;;;;;;;;;;;&     .;;;;;;;;=         -;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;;.  ",
+" @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*@@+*;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@+             &;;;;;;;;;%       +;;;;;;;;;=     +;;;;;;;;*     +;;;;;;;;;;;;;;;;;;;;;;;;;;;;     .;;;;;;;;=       +-;;;;;;;;;$    &;;;;;;;;;;;;;;;;;;;;;;;;;;;*  ",
+" @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+$=;;;-&@@@@&;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@.             .;;;;;;;;;;-@   .*;;;;;;;;;;%     +;;;;;;;;*     *;;;;;;;;;;;;;;;;;;;;;;;;;;;;.    .;;;;;;;;-&&&&&*;;;;;;;;;;;;     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ",
+" +@@@@@@@@@*;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@+@@@@@;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@               &;;;;;;;;;;;;;;;;;;;;;;;;;;      +;;;;;;;;*    .;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;$    #;;;;;;;;;;;;;;;;;;;;;;;;;;;;;. ",
+" .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;@      +;;;;;;;;*    $;;;;;;;;%            ;;;;;;;;;    .;;;;;;;;;;;;;;;;;;;;;;;;;-     *;;;;;;;;            .;;;;;;;;* ",
+"  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;&       +;;;;;;;;*    *;;;;;;;;             &;;;;;;;;#   .;;;;;;;;;;;;;;;;;;;;;;;;;      ;;;;;;;;=             -;;;;;;;;.",
+"  +@@@@@@@@@%;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@.                 #;;;;;;;;;;;;;;;;;;;;;%        +;;;;;;;;*    ;;;;;;;;*              ;;;;;;;;*   .;;;;;;;;;;;;;;;;;;;;;;;-      %;;;;;;;;%             %;;;;;;;;#",
+"  .@@@@@@@@@@;;;;;;;;;;;;;;;;&+@@@@@@@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@@@                   .-;;;;;;;;;;;;;;;;;;+         +;;;;;;;;*   &;;;;;;;;$              =;;;;;;;;   .;;;;;;;;;;;;;;;;;;;;;;%       -;;;;;;;;               ;;;;;;;;*",
+"   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@+;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@@+                     $=;;;;;;;;;;;;;=$           .;;;;;;;;*   =;;;;;;;;               $;;;;;;;;#  .;;;;;;;;;;;;;;;;;;;=%.        ;;;;;;;;&               *;;;;;;;;",
+"   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-#+@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@.                       .%=---;---=%.              %&&&&&&&.   +&&&&&&&.                $&&&&&&%    #&&&&&&&&&&&&&&%$+            $&&&&&&%                 %&&&&&&#",
+"   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;=+@@@@@@                                                                                                                                                                   ",
+"    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;=%++@@@@@@@+@;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@.                                                                                                                                                                   ",
+"    .@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;=&%%$%%&*-;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@                                                                                                                                                                    ",
+"     +@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@.                                                                                                                                                                    ",
+"      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@+                                                                                                                                                                     ",
+"      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@                                                                                                                                                                      ",
+"       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                      ",
+"       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@                                                                                                                                                                       ",
+"        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@                                                                                                                                                                        ",
+"         +@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                        ",
+"          @@@@@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%+@@@+                                                                                                                                                                         ",
+"           @@@@@@@@@@@@@+#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-#@@@@+                                                                                                                                                                          ",
+"           .@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@                                                                                                                                                                           ",
+"            .@@@@@@@@@@@@@@@@$-;;;;;;;;;;;;;;;;;;;;;;;;*$%*-;;;-*$@@@@@@@                                                                                                                                                                            ",
+"             .@@@@@@@@@@@@@@@@+#&-;;;;;;;;;;;;;;;;;;=%@+@@+++.+++@@@@@@+                                                                                                                                                                             ",
+"               @@@@@@@@@@@@@@@@@@++%*--;;;;;;;;--&#++@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
+"                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
+"                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
+"                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
+"                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
+"                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
+"                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
+"                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
+"                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
+"                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
+"                                   ...+++@@@@++...                                                                                                                                                                                                   "};
+
+
+const char* loopRepeat_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -152,7 +160,7 @@ const char *loopRepeat_xpm[] = {
 ".................."};
 
 
-const char *loopBasic_xpm[] = {
+const charloopBasic_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -182,7 +190,7 @@ const char *loopBasic_xpm[] = {
 ".................."};
 
 
-const char *loopOnce_xpm[] = {
+const charloopOnce_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -212,7 +220,7 @@ const char *loopOnce_xpm[] = {
 ".................."};
 
 
-const char *loopOnceBar_xpm[] = {
+const charloopOnceBar_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #393A38",
@@ -242,7 +250,7 @@ const char *loopOnceBar_xpm[] = {
 "                  "};
 
 
-const char *oneshotBasic_xpm[] = {
+const charoneshotBasic_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -272,7 +280,7 @@ const char *oneshotBasic_xpm[] = {
 ".................."};
 
 
-const char *oneshotRetrig_xpm[] = {
+const charoneshotRetrig_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -302,7 +310,7 @@ const char *oneshotRetrig_xpm[] = {
 ".................."};
 
 
-const char *oneshotPress_xpm[] = {
+const charoneshotPress_xpm[] = {
 "18 18 8 1",
 "      c #181917",
 ".     c #242523",
@@ -332,7 +340,7 @@ const char *oneshotPress_xpm[] = {
 ".................."};
 
 
-const char *oneshotEndless_xpm[] = {
+const charoneshotEndless_xpm[] = {
 "18 18 6 1",
 "      c #242523",
 ".     c #464745",
@@ -360,7 +368,7 @@ const char *oneshotEndless_xpm[] = {
 "                  "};
 
 
-const char *updirOff_xpm[] = {
+const charupdirOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #332F2E",
@@ -390,7 +398,7 @@ const char *updirOff_xpm[] = {
 "                  "};
 
 
-const char *updirOn_xpm[] = {
+const charupdirOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #555150",
@@ -420,7 +428,7 @@ const char *updirOn_xpm[] = {
 "                  "};
 
 
-const char *pause_xpm[] = {
+const charpause_xpm[] = {
 "23 23 8 1",
 "      c #4D4F4C",
 ".     c #514E53",
@@ -455,7 +463,7 @@ const char *pause_xpm[] = {
 "                       "};
 
 
-const char *play_xpm[] = {
+const charplay_xpm[] = {
 "23 23 8 1",
 "      c #242523",
 ".     c #393534",
@@ -490,7 +498,7 @@ const char *play_xpm[] = {
 "                       "};
 
 
-const char *rewindOff_xpm[] = {
+const charrewindOff_xpm[] = {
 "23 23 8 1",
 "      c #242523",
 ".     c #393534",
@@ -525,7 +533,7 @@ const char *rewindOff_xpm[] = {
 "                       "};
 
 
-const char *rewindOn_xpm[] = {
+const charrewindOn_xpm[] = {
 "23 23 8 1",
 "      c #4D4F4C",
 ".     c #514E53",
@@ -560,96 +568,84 @@ const char *rewindOn_xpm[] = {
 "                       "};
 
 
-// 18x18
-/*
-const unsigned char giada_icon[] = {
-   0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
-   0x3e, 0xf0, 0x01, 0x1e, 0xe0, 0x01, 0x0e, 0xc3, 0x01, 0x8e, 0xff, 0x01,
-   0x8e, 0xc1, 0x01, 0x8e, 0xc1, 0x01, 0x8e, 0xc7, 0x01, 0x0e, 0xc7, 0x01,
-   0x1e, 0xc0, 0x01, 0x3e, 0xf0, 0x01, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01,
-   0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 };
-*/
-
-const char *giada_icon[] = {
-"65 65 11 1",
-"      c None",
-".     c #000000",
-"+     c #000100",
-"@     c #FFFFFF",
-"#     c #FDFFFC",
-"$     c #CBCDC9",
-"%     c #292B28",
-"&     c #626461",
-"*     c #484A47",
-"=     c #888A87",
-"-     c #A7A9A6",
-"....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++....",
-".@@@#####################$%+++++++++++++%&&*%+++++++&##%+++++....",
-".@@#####################&++++++++++++=$#######-*+++++&$+++++++...",
-".@@####################&++++++++++%-############$*+++++++++++++..",
-"+#####################*++++++++++&################-++++++++++++%+",
-"+####################*++++++++++=##################$+++++++++++*+",
-"+###################*++++++++++$####################$++++++++++=+",
-"+##################=++++++++++-######################-+++++++++-+",
-"+#################$++++++++++=#######################=+++++++++$+",
-"+#################%+++++++++*########################*+++++++++#+",
-"+################*++++++++++#########################%++++++++*#+",
-"+###############-++++++++++=########################$+++++++++&#+",
-"+###############%+++++++++%#########################-+++++++++-#+",
-"+##############-++++++++++-#########################&+++++++++$#+",
-"+##############%+++++++++%##########################*+++++++++##+",
-"+#############-++++++++++-##########################+++++++++%##+",
-"+#############%++++++++++##########################$+++++++++*##+",
-"+############$++++++++++&##########################=+++++++++=##+",
-"+############=++++++++++$##########################&+++++++++-##+",
-"+############*+++++++++%###########################%+++++++++$##+",
-"+############++++++++++=###########################++++++++++###+",
-"+###########$++++++++++$##########################-+++++++++*###+",
-"+###########=++++++++++###########################=+++++++++&###+",
-"+###########*+++++++++%###########################*+++++++++-###+",
-"+###########%+++++++++&###########################++++++++++$###+",
-"+###########%+++++++++-##########################=++++++++++####+",
-"+###########++++++++++$##########################%+++++++++%####+",
-"+###########++++++++++##########################$++++++++++&####+",
-"+##########$++++++++++##########################&++++++++++=####+",
-"+##########$+++++++++%#########################$+++++++++++-####+",
-"+##########$+++++++++%#########################&+++++++++++$####+",
-"+###########+++++++++*########################$++++++++++++#####+",
-"+###########+++++++++*########################*+++++++++++*#####+",
-"+###########%++++++++%#######################=++++++++++++&#####+",
-"+###########&+++++++++######################$+++++++++++++-#####+",
-"+###########=+++++++++$#####################%+++%+++++++++$#####+",
-"+###########$+++++++++$####################&+++%=+++++++++######+",
-"+############%++++++++&###################=++++$&++++++++%######+",
-"+############-+++++++++$#################&++++=#*++++++++&######+",
-"+#############+++++++++&################*++++*##+++++++++=######+",
-"+#############=+++++++++-#############$%++++%###+++++++++-######+",
-"+##############*+++++++++=##########$*+++++%###$+++++++++#######+",
-"+###############++++++++++&$######$&++++++&####=+++++++++#######+",
-"+###############$++++++++++++%&*%++++++++=#####&++++++++*#######+",
-"+################$%+++++++++++++++++++++-######%++++++++=#######+",
-"+##################&++++++++++++++++++=########+++++++++-#######+",
-"+###################$%+++++++++++++%=#########$+++++++++########+",
-"+#####################$=%++++++%*=-###########=++++++++%########+",
-"+##########################$$$################*++++++++&########+",
-"+#############################################+++++++++=########+",
-"+############################################$+++++++++$########+",
-"+############################################&++++++++%#########+",
-"+############################################+++++++++=#########+",
-"+###########################################=+++++++++##########+",
-"+###########################################%++++++++*##########+",
-"+##########################################=+++++++++-##########+",
-"+#########-==$############################$+++++++++&###########+",
-"+#######=++++++-##########################*+++++++++############+",
-"+######$++++++++$########################=+++++++++-############+",
-"+######=+++++++++$######################-+++++++++&#############+",
-"+######=+++++++++*#####################$+++++++++&##############.",
-".@#####=++++++++++-###################-+++++++++=##############@.",
-".@@####=++++++++++%##################=+++++++++=#############@@@.",
-".@@@###=+++++++++++*###############$*++++++++%$##############@@@.",
-"....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....."};
-
-const char *recOff_xpm[] = {
+const char* giada_icon[] = {
+"65 65 8 1",
+"      c #444643",
+".     c #565755",
+"+     c #6C6E6B",
+"@     c #898B88",
+"#     c #A3A5A2",
+"$     c #BEC0BD",
+"%     c #D7DAD6",
+"&     c #FCFEFB",
+"                                                                 ",
+" &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
+" &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
+" &&&&&&&&&&$              ...+@@#@@+..              +%&&&&&&&&&& ",
+" &&&&&&&&&#            .+#$&&&&&&&&&&%$@+.           .%&&&&&&&&& ",
+" &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@.          .%&&&&&&&& ",
+" &&&&&&&#          .#%&&&&&&&&&&&&&&&&&&&&&%@          .%&&&&&&& ",
+" &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&%+         .&&&&&&& ",
+" &&&&&%          $&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@         +&&&&&& ",
+" &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         @&&&&& ",
+" &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         $&&&& ",
+" &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        +&&&& ",
+" &&&+        %&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        #&&& ",
+" &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&@       +%&& ",
+" &%+       @&&&&&&&&&&&&&&%@..    ..+#&&&&&&&&&&&&&&%.       #&& ",
+" &$       .%&&&&&&&&&&&&%+             #&&&&&&&&&&&&&#       +&& ",
+" &@       $&&&&&&&&&&&&#                +%&&&&&&&&&&&%+       $& ",
+" %.      +%&&&&&&&&&&&@                  .$&&&&&&&&&&&#       @& ",
+" $       #&&&&&&&&&&&@                    .$&&&&&&&&&&&+       & ",
+" @      .%&&&&&&&&&&#                      .%&&&&&&&&&&@       $ ",
+" .      +&&&&&&&&&&%                        +&&&&&&&&&&%.      @ ",
+"        #&&&&&&&&&&+         @%&&%$+         #&&&&&&&&&&.      . ",
+"       .%&&&&&&&&&$        +%&&&&&&&#        .&&&&&&&&&&@        ",
+"       .&&&&&&&&&&+       +&&&&&&&&&&$        $&&&&&&&&&$        ",
+"       +&&&&&&&&&&       .%&&&&&&&&&&&#       @&&&&&&&&&%        ",
+"       @&&&&&&&&&$       @&&&&&&&&&&&&&.      +&&&&&&&&&&        ",
+"       @&&&&&&&&&#       %&&&&&&&&&&&&&#      .%&&&&&&&&&.       ",
+"       #&&&&&&&&&@      .&&&&&&&&&&&&&&$      .%&&&&&&&&&.       ",
+"       #&&&&&&&&&@      .&&&&&&&&&&&&&&%      .#$%&&&&&&&+       ",
+"       #&&&&&&&&&@      .&&&&&&&&&&&&&&$           @%&&&&.       ",
+"       @&&&&&&&&&#       %&&&&&&&&&&&&&#             @%&&.       ",
+"       @&&&&&&&&&$       #&&&&&&&&&&&&&.   +@@@@+.    .$&        ",
+"       +&&&&&&&&&&       .%&&&&&&&&&&&#  +$%&&&&&%#.   .$        ",
+"       .&&&&&&&&&&+       +&&&&&&&&&&$  $&&&&&&&&&&%@   .        ",
+"       .%&&&&&&&&&$        +%&&&&&&&#. %&&&&&&&&&&&&&#           ",
+"        #&&&&&&&&&&+         @%&&&$+  $&&&&&&&&&&&&&&&@        . ",
+" .      +&&&&&&&&&&%                 @&&&&&&&&&&&&&&&&%.       @ ",
+" @      .%&&&&&&&&&&#                %&&&&&&&&&&&&&&&&&@       $ ",
+" $       #&&&&&&&&&&&@              @&&&&&&&&&&&&&&&&&&%.      & ",
+" %.      +%&&&&&&&&&&&@             $&&&&&&&&&&&&&&&&&&&.     @& ",
+" &@       $&&&&&&&&&&&&#            %&&&&&&&&&&&&&&&&&&&+     $& ",
+" &$       .%&&&&&&&&&&&&%+          %&&&&&&&&&&&&&&&&&&&@    +&& ",
+" &%+       @&&&&&&&&&&&&&&%@..     .%&&&&&&&&&&&&&&&&&&&@    #&& ",
+" &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&&&&&+   +%&& ",
+" &&&+       .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.   #&&& ",
+" &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   +&&&& ",
+" &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+   $&&&& ",
+" &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   @&&&&& ",
+" &&&&&%         .$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  +&&&&&& ",
+" &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  .&&&&&&& ",
+" &&&&&&&#          .$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&%#   .%&&&&&&& ",
+" &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@#$%%$$@+   .%&&&&&&&& ",
+" &&&&&&&&&#            .+#%&&&&&&&&&&&$@+.  ....     .%&&&&&&&&& ",
+" &&&&&&&&&&$              ..+@@###@+...             +%&&&&&&&&&& ",
+" &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
+" &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
+"                                                                 "};
+
+
+const char* recOff_xpm[] = {
 "23 23 8 1",
 "      c #242523",
 ".     c #342F2E",
@@ -683,7 +679,7 @@ const char *recOff_xpm[] = {
 "                       ",
 "                       "};
 
-const char *recOn_xpm[] = {
+const charrecOn_xpm[] = {
 "23 23 8 1",
 "      c #4D4F4C",
 ".     c #5F4E50",
@@ -717,7 +713,7 @@ const char *recOn_xpm[] = {
 "                       ",
 "                       "};
 
-const char *inputRecOn_xpm[] = {
+const charinputRecOn_xpm[] = {
 "23 23 8 1",
 "      c #524D4C",
 ".     c #4D4F4C",
@@ -751,7 +747,7 @@ const char *inputRecOn_xpm[] = {
 ".......................",
 "......................."};
 
-const char *inputRecOff_xpm[] = {
+const charinputRecOff_xpm[] = {
 "23 23 8 1",
 "      c #242523",
 ".     c #252724",
@@ -785,7 +781,7 @@ const char *inputRecOff_xpm[] = {
 "                       ",
 "                       "};
 
-const char *inputToOutputOn_xpm[] = {
+const charinputToOutputOn_xpm[] = {
 "10 10 8 1",
 "      c #4D4F4C",
 ".     c #585A57",
@@ -806,7 +802,7 @@ const char *inputToOutputOn_xpm[] = {
 "          ",
 "          "};
 
-const char *inputToOutputOff_xpm[] = {
+const charinputToOutputOff_xpm[] = {
 "10 10 8 1",
 "      c #242523",
 ".     c #2E302D",
@@ -827,7 +823,7 @@ const char *inputToOutputOff_xpm[] = {
 "          ",
 "          "};
 
-const char *muteOff_xpm[] = {
+const charmuteOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #2E2F2D",
@@ -856,7 +852,7 @@ const char *muteOff_xpm[] = {
 "                  ",
 "                  "};
 
-const char *muteOn_xpm[] = {
+const charmuteOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #585A57",
@@ -886,7 +882,7 @@ const char *muteOn_xpm[] = {
 "                  "};
 
 
-const char *readActionOff_xpm[] = {
+const charreadActionOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #393B38",
@@ -916,7 +912,7 @@ const char *readActionOff_xpm[] = {
 "                  "};
 
 
-const char *readActionOn_xpm[] = {
+const charreadActionOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #696B68",
@@ -946,7 +942,7 @@ const char *readActionOn_xpm[] = {
 "                  "};
 
 
-const char *metronomeOff_xpm[] = {
+const charmetronomeOff_xpm[] = {
 "13 13 8 1",
 "      c #242523",
 ".     c #2D2928",
@@ -971,7 +967,7 @@ const char *metronomeOff_xpm[] = {
 "             "};
 
 
-const char *metronomeOn_xpm[] = {
+const charmetronomeOn_xpm[] = {
 "13 13 8 1",
 "      c #4D4F4C",
 ".     c #565150",
@@ -996,7 +992,7 @@ const char *metronomeOn_xpm[] = {
 "             "};
 
 
-const char *zoomInOff_xpm[] = {
+const charzoomInOff_xpm[] = {
 "18 18 8 1",
 "      c None",
 ".     c #252525",
@@ -1026,7 +1022,7 @@ const char *zoomInOff_xpm[] = {
 "++++++++++++++++++"};
 
 
-const char *zoomInOn_xpm[] = {
+const charzoomInOn_xpm[] = {
 "18 18 8 1",
 "      c None",
 ".     c #4E4E4E",
@@ -1056,7 +1052,7 @@ const char *zoomInOn_xpm[] = {
 ".................."};
 
 
-const char *zoomOutOff_xpm[] = {
+const charzoomOutOff_xpm[] = {
 "18 18 5 1",
 "      c None",
 ".     c #252525",
@@ -1083,7 +1079,7 @@ const char *zoomOutOff_xpm[] = {
 "++++++++++++++++++"};
 
 
-const char *zoomOutOn_xpm[] = {
+const charzoomOutOn_xpm[] = {
 "18 18 4 1",
 "      c None",
 ".     c #4E4E4E",
@@ -1110,7 +1106,7 @@ const char *zoomOutOn_xpm[] = {
 
 
 
-const char *scrollRightOff_xpm[] = {
+const charscrollRightOff_xpm[] = {
 "12 12 8 1",
 "      c #181917",
 ".     c #242523",
@@ -1134,7 +1130,7 @@ const char *scrollRightOff_xpm[] = {
 "............"};
 
 
-const char *scrollLeftOff_xpm[] = {
+const charscrollLeftOff_xpm[] = {
 "12 12 8 1",
 "      c #181917",
 ".     c #242523",
@@ -1158,7 +1154,7 @@ const char *scrollLeftOff_xpm[] = {
 "............"};
 
 
-const char *scrollLeftOn_xpm[] = {
+const charscrollLeftOn_xpm[] = {
 "12 12 8 1",
 "      c #4D4F4C",
 ".     c #6B6D6A",
@@ -1182,7 +1178,7 @@ const char *scrollLeftOn_xpm[] = {
 "            "};
 
 
-const char *scrollRightOn_xpm[] = {
+const charscrollRightOn_xpm[] = {
 "12 12 8 1",
 "      c #4D4F4C",
 ".     c #6B6D6A",
@@ -1206,7 +1202,7 @@ const char *scrollRightOn_xpm[] = {
 "            "};
 
 
-const char *soloOn_xpm[] = {
+const charsoloOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #616360",
@@ -1236,7 +1232,7 @@ const char *soloOn_xpm[] = {
 "                  "};
 
 
-const char *soloOff_xpm[] = {
+const charsoloOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #3D3F3D",
@@ -1269,7 +1265,7 @@ const char *soloOff_xpm[] = {
 #ifdef WITH_VST
 
 
-const char *fxOff_xpm[] = {
+const charfxOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #40423F",
@@ -1299,7 +1295,7 @@ const char *fxOff_xpm[] = {
 "                  "};
 
 
-const char *fxOn_xpm[] = {
+const charfxOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #565855",
@@ -1329,7 +1325,7 @@ const char *fxOn_xpm[] = {
 "                  "};
 
 
-const char *fxShiftUpOff_xpm[] = {
+const charfxShiftUpOff_xpm[] = {
 "18 18 7 1",
 "      c #242523",
 ".     c #4D4F4C",
@@ -1358,7 +1354,7 @@ const char *fxShiftUpOff_xpm[] = {
 "                  "};
 
 
-const char *fxShiftUpOn_xpm[] = {
+const charfxShiftUpOn_xpm[] = {
 "18 18 5 1",
 "      c #4D4F4C",
 ".     c #70726F",
@@ -1385,7 +1381,7 @@ const char *fxShiftUpOn_xpm[] = {
 "                  "};
 
 
-const char *fxShiftDownOff_xpm[] = {
+const charfxShiftDownOff_xpm[] = {
 "18 18 7 1",
 "      c #242523",
 ".     c #4D4F4C",
@@ -1414,7 +1410,7 @@ const char *fxShiftDownOff_xpm[] = {
 "                  "};
 
 
-const char *fxShiftDownOn_xpm[] = {
+const charfxShiftDownOn_xpm[] = {
 "18 18 5 1",
 "      c #4D4F4C",
 ".     c #70726F",
@@ -1441,7 +1437,7 @@ const char *fxShiftDownOn_xpm[] = {
 "                  "};
 
 
-const char *vstLogo_xpm[] = {
+const charvstLogo_xpm[] = {
 "65 38 8 1",
 "      c #161715",
 ".     c #2B2D2A",
@@ -1491,7 +1487,7 @@ const char *vstLogo_xpm[] = {
 "                     ..........  .@@@@@@@@                       "};
 
 
-const char *fxRemoveOff_xpm[] = {
+const charfxRemoveOff_xpm[] = {
 "18 18 9 1",
 "      c None",
 ".     c #242623",
@@ -1522,7 +1518,7 @@ const char *fxRemoveOff_xpm[] = {
 ".................."};
 
 
-const char *fxRemoveOn_xpm[] = {
+const charfxRemoveOn_xpm[] = {
 "18 18 9 1",
 "      c None",
 ".     c #4D4F4C",
@@ -1554,7 +1550,7 @@ const char *fxRemoveOn_xpm[] = {
 #endif // #ifdef WITH_VST
 
 
-const char *divideOn_xpm[] = {
+const chardivideOn_xpm[] = {
 "18 18 7 1",
 "      c #5A5A5A",
 ".     c #696969",
@@ -1583,7 +1579,7 @@ const char *divideOn_xpm[] = {
 "                  "};
 
 
-const char *divideOff_xpm[] = {
+const chardivideOff_xpm[] = {
 "18 18 8 1",
 "      c #252525",
 ".     c #3B3B3B",
@@ -1613,7 +1609,7 @@ const char *divideOff_xpm[] = {
 "                  "};
 
 
-const char *multiplyOn_xpm[] = {
+const charmultiplyOn_xpm[] = {
 "18 18 8 1",
 "      c #595B58",
 ".     c #737572",
@@ -1643,7 +1639,7 @@ const char *multiplyOn_xpm[] = {
 "                  "};
 
 
-const char *multiplyOff_xpm[] = {
+const charmultiplyOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #4A4C49",
@@ -1673,7 +1669,7 @@ const char *multiplyOff_xpm[] = {
 "                  "};
 
 
-const char *channelStop_xpm[] = {
+const charchannelStop_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #312D2C",
@@ -1704,7 +1700,7 @@ const char *channelStop_xpm[] = {
 
 
 
-const char *channelPlay_xpm[] = {
+const charchannelPlay_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #554E56",
@@ -1734,7 +1730,7 @@ const char *channelPlay_xpm[] = {
 "                  "};
 
 
-const char *armOff_xpm[] = {
+const chararmOff_xpm[] = {
 "18 18 8 1",
 "      c #242523",
 ".     c #4F4445",
@@ -1764,7 +1760,7 @@ const char *armOff_xpm[] = {
 "                  "};
 
 
-const char *armOn_xpm[] = {
+const chararmOn_xpm[] = {
 "18 18 8 1",
 "      c #4D4F4C",
 ".     c #6B5077",
index a09cdb7d5159b2b79519e915a6b5c34083f1130e..5fae68b566fe0e00c18a286548d7b65eeb688a2d 100644 (file)
 #ifndef G_GRAPHICS_H
 #define G_GRAPHICS_H
 
-extern const char *giada_logo_xpm[];
+extern const chargiada_logo_xpm[];
 
-extern const char *loopRepeat_xpm[];
-extern const char *loopBasic_xpm[];
-extern const char *loopOnce_xpm[];
-extern const char *loopOnceBar_xpm[];
-extern const char *oneshotBasic_xpm[];
-extern const char *oneshotRetrig_xpm[];
-extern const char *oneshotPress_xpm[];
-extern const char *oneshotEndless_xpm[];
+extern const charloopRepeat_xpm[];
+extern const charloopBasic_xpm[];
+extern const charloopOnce_xpm[];
+extern const charloopOnceBar_xpm[];
+extern const charoneshotBasic_xpm[];
+extern const charoneshotRetrig_xpm[];
+extern const charoneshotPress_xpm[];
+extern const charoneshotEndless_xpm[];
 
-extern const char *updirOff_xpm[];
-extern const char *updirOn_xpm[];
+extern const charupdirOff_xpm[];
+extern const charupdirOn_xpm[];
 
-extern const char *pause_xpm[];
-extern const char *play_xpm[];
+extern const charpause_xpm[];
+extern const charplay_xpm[];
 
-extern const char *zoomInOff_xpm[];
-extern const char *zoomInOn_xpm[];
-extern const char *zoomOutOff_xpm[];
-extern const char *zoomOutOn_xpm[];
+extern const charzoomInOff_xpm[];
+extern const charzoomInOn_xpm[];
+extern const charzoomOutOff_xpm[];
+extern const charzoomOutOn_xpm[];
 
-extern const char *scrollLeftOff_xpm[];
-extern const char *scrollLeftOn_xpm[];
-extern const char *scrollRightOff_xpm[];
-extern const char *scrollRightOn_xpm[];
+extern const charscrollLeftOff_xpm[];
+extern const charscrollLeftOn_xpm[];
+extern const charscrollRightOff_xpm[];
+extern const charscrollRightOn_xpm[];
 
-extern const char *rewindOff_xpm[];
-extern const char *rewindOn_xpm[];
+extern const charrewindOff_xpm[];
+extern const charrewindOn_xpm[];
 
-extern const char *recOff_xpm[];
-extern const char *recOn_xpm[];
+extern const charrecOff_xpm[];
+extern const charrecOn_xpm[];
 
-extern const char *metronomeOff_xpm[];
-extern const char *metronomeOn_xpm[];
+extern const charmetronomeOff_xpm[];
+extern const charmetronomeOn_xpm[];
 
-extern const char *inputRecOn_xpm[];
-extern const char *inputRecOff_xpm[];
+extern const charinputRecOn_xpm[];
+extern const charinputRecOff_xpm[];
 
-extern const char *inputToOutputOn_xpm[];
-extern const char *inputToOutputOff_xpm[];
+extern const charinputToOutputOn_xpm[];
+extern const charinputToOutputOff_xpm[];
 
-extern const char *divideOn_xpm[];
-extern const char *divideOff_xpm[];
-extern const char *multiplyOn_xpm[];
-extern const char *multiplyOff_xpm[];
+extern const chardivideOn_xpm[];
+extern const chardivideOff_xpm[];
+extern const charmultiplyOn_xpm[];
+extern const charmultiplyOff_xpm[];
 
-extern const char *muteOff_xpm[];
-extern const char *muteOn_xpm[];
+extern const charmuteOff_xpm[];
+extern const charmuteOn_xpm[];
 
-extern const char *soloOff_xpm[];
-extern const char *soloOn_xpm[];
+extern const charsoloOff_xpm[];
+extern const charsoloOn_xpm[];
 
-extern const char *armOff_xpm[];
-extern const char *armOn_xpm[];
+extern const chararmOff_xpm[];
+extern const chararmOn_xpm[];
 
-extern const char *readActionOn_xpm[];
-extern const char *readActionOff_xpm[];
+extern const charreadActionOn_xpm[];
+extern const charreadActionOff_xpm[];
 
-extern const char *channelStop_xpm[];
-extern const char *channelPlay_xpm[];
+extern const charchannelStop_xpm[];
+extern const charchannelPlay_xpm[];
 
 #ifdef WITH_VST
-extern const char *fxOff_xpm[];
-extern const char *fxOn_xpm[];
+extern const charfxOff_xpm[];
+extern const charfxOn_xpm[];
 
-extern const char *fxShiftUpOn_xpm[];
-extern const char *fxShiftUpOff_xpm[];
-extern const char *fxShiftDownOn_xpm[];
-extern const char *fxShiftDownOff_xpm[];
+extern const charfxShiftUpOn_xpm[];
+extern const charfxShiftUpOff_xpm[];
+extern const charfxShiftDownOn_xpm[];
+extern const charfxShiftDownOff_xpm[];
 
-extern const char *fxRemoveOff_xpm[];
-extern const char *fxRemoveOn_xpm[];
+extern const charfxRemoveOff_xpm[];
+extern const charfxRemoveOn_xpm[];
 
-extern const char *vstLogo_xpm[];
+extern const charvstLogo_xpm[];
 #endif
 
-extern const char *giada_icon[];
+extern const chargiada_icon[];
 
 #endif
index 4c83b02bcdfaee5d73a4d93282291a29ff596136..3dd4867d91d11a97d503e58a976e3f9d5e7300c6 100644 (file)
@@ -121,7 +121,7 @@ void MidiChannel::rewindBySeq()
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::setMute(bool value, EventType eventType)
+void MidiChannel::setMute(bool value)
 {
        midiChannelProc::setMute(this, value);
 }
@@ -221,7 +221,7 @@ void MidiChannel::receiveMidi(const MidiEvent& midiEvent)
        while (true) {
                if (pthread_mutex_trylock(&pluginHost::mutex_midi) != 0)
                        continue;
-               gu_log("[Channel::processMidi] msg=%X\n", midiEventFlat.getRaw());
+               gu_log("[MidiChannel::processMidi] msg=%X\n", midiEventFlat.getRaw());
                addVstMidiEvent(midiEventFlat.getRaw(), 0);
                pthread_mutex_unlock(&pluginHost::mutex_midi);
                break;
index 08f272935f15686b30dab313ddb6949387b243e5..7185397bb025abade5d3f8ea5181f7063a3c3633 100644 (file)
@@ -55,7 +55,7 @@ public:
        void stopBySeq(bool chansStopOnSeqHalt) override;
        void stop() override {};
        void rewindBySeq() override;
-       void setMute(bool value, giada::EventType eventType) override;
+       void setMute(bool value) override;
        void readPatch(const std::string& basePath, int i) override;
        void writePatch(int i, bool isProject) override;
        void receiveMidi(const giada::m::MidiEvent& midiEvent) override;
index e5d93ea15942be2e3291acd973e4c984f3ed1341..201a3855f7a097141382ab88ab297056645a0b4d 100644 (file)
@@ -66,10 +66,7 @@ void* cb_data = nullptr;
 
 void processPlugins(Channel* ch, const MidiEvent& midiEvent)
 {
-       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
-       'velocy' byte. Otherwise strip it off. */
-
-       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+       uint32_t pure = midiEvent.getRawNoVelocity();
 
        /* Plugins' parameters layout reflects the structure of the matrix
        Channel::midiInPlugins. It is safe to assume then that i (i.e. Plugin*) and k 
@@ -99,10 +96,7 @@ void processPlugins(Channel* ch, const MidiEvent& midiEvent)
 
 void processChannels(const MidiEvent& midiEvent)
 {
-       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
-       'velocy' byte. Otherwise strip it off. */
-
-       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+       uint32_t pure = midiEvent.getRawNoVelocity();
 
        for (Channel* ch : mixer::channels) {
 
@@ -158,11 +152,13 @@ void processChannels(const MidiEvent& midiEvent)
                }
 
 #ifdef WITH_VST
-               processPlugins(ch, midiEvent); // Process plugins' parameters
+
+               /* Process learned plugins parameters. */
+               processPlugins(ch, midiEvent); 
+
 #endif
 
                /* Redirect full midi message (pure + velocity) to plugins. */
-
                ch->receiveMidi(midiEvent.getRaw());
        }
 }
@@ -173,10 +169,7 @@ void processChannels(const MidiEvent& midiEvent)
 
 void processMaster(const MidiEvent& midiEvent)
 {
-       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
-       'velocy' byte. Otherwise strip it off. */
-
-       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+       uint32_t pure = midiEvent.getRawNoVelocity();
 
        if      (pure == conf::midiInRewind) {
                gu_log("  >>> rewind (master) (pure=0x%X)\n", pure);
@@ -251,22 +244,24 @@ void stopMidiLearn()
 void dispatch(int byte1, int byte2, int byte3)
 {
        /* Here we want to catch two things: a) note on/note off from a keyboard and 
-       b) knob/wheel/slider movements from a controller. */
+       b) knob/wheel/slider movements from a controller. 
+       We must also fix the velocity zero issue for those devices that sends NOTE
+       OFF events as NOTE ON + velocity zero. Let's make it a real NOTE OFF event. */
 
        MidiEvent midiEvent(byte1, byte2, byte3);
+       midiEvent.fixVelocityZero();
 
        gu_log("[midiDispatcher] MIDI received - 0x%X (chan %d)\n", midiEvent.getRaw(), 
                midiEvent.getChannel());
 
        /* Start dispatcher. If midi learn is on don't parse channels, just learn 
-       incoming MIDI signal. Learn callback wants 'pure' MIDI event: if 'noNoteOff' 
-       in global config, get the raw value with the 'velocy' byte. Otherwise strip it 
-       off. If midi learn is off process master events first, then each channel 
-       in the stack. This way incoming signals don't get processed by glue_* when 
-       MIDI learning is on. */
+       incoming MIDI signal. Learn callback wants 'pure' MIDI event, i.e. with
+       velocity value stripped off. If midi learn is off process master events first, 
+       then each channel in the stack. This way incoming signals don't get processed 
+       by glue_* when MIDI learning is on. */
 
        if (cb_learn)
-               cb_learn(midiEvent.getRaw(conf::noNoteOff), cb_data);
+               cb_learn(midiEvent.getRawNoVelocity(), cb_data);
        else {
                processMaster(midiEvent);
                processChannels(midiEvent);
index ae11319d3d9e52a7e5e1c59cf70dfa421dd95a42..ac3aabc47b3a4b9f764c152fc0fa020c54393535 100644 (file)
@@ -25,6 +25,7 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include "midiEvent.h"
 
 
@@ -32,8 +33,7 @@ namespace giada {
 namespace m
 {
 MidiEvent::MidiEvent()
-       : m_raw     (0x0),
-         m_status  (0),
+       : m_status  (0),
          m_channel (0),
          m_note    (0),
          m_velocity(0),
@@ -46,8 +46,7 @@ MidiEvent::MidiEvent()
 
 
 MidiEvent::MidiEvent(uint32_t raw)
-       : m_raw     (raw),
-         m_status  ((raw & 0xF0000000) >> 24),
+       : m_status  ((raw & 0xF0000000) >> 24),
          m_channel ((raw & 0x0F000000) >> 24),
          m_note    ((raw & 0x00FF0000) >> 16),
          m_velocity((raw & 0x0000FF00) >> 8),
@@ -58,6 +57,7 @@ MidiEvent::MidiEvent(uint32_t raw)
 
 /* -------------------------------------------------------------------------- */
 
+
 MidiEvent::MidiEvent(int byte1, int byte2, int byte3)
        : MidiEvent((byte1 << 24) | (byte2 << 16) | (byte3 << 8) | (0x00))
 {
@@ -78,10 +78,28 @@ void MidiEvent::resetDelta()
 
 void MidiEvent::setChannel(int c)
 {
+       assert(c >= 0 && c < G_MAX_MIDI_CHANS);
        m_channel = c;
 }
 
 
+void MidiEvent::setVelocity(int v)
+{
+       assert(v >= 0 && v < G_MAX_VELOCITY);
+       m_velocity = v;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiEvent::fixVelocityZero()
+{
+       if (m_status == NOTE_ON && m_velocity == 0)
+               m_status = NOTE_OFF;
+}
+
+
 /* -------------------------------------------------------------------------- */
 
 
@@ -121,11 +139,18 @@ int MidiEvent::getDelta() const
 }
 
 
-uint32_t MidiEvent::getRaw(bool velocity) const
+/* -------------------------------------------------------------------------- */
+
+
+uint32_t MidiEvent::getRaw() const
+{
+       return (m_status << 24) | (m_channel << 24) | (m_note << 16) | (m_velocity << 8) | (0x00);
+}
+
+
+uint32_t MidiEvent::getRawNoVelocity() const
 {
-       if (!velocity)
-               return m_raw & 0xFFFF0000;
-       return m_raw;
+       return (m_status << 24) | (m_channel << 24) | (m_note << 16) | (0x00 << 8) | (0x00);
 }
 
 
index fb31369eba1053e39af55d6991c85e24d3d9c6fc..4c29e5241c32465a31375ff303f5225693eef2c5 100644 (file)
@@ -39,7 +39,7 @@ class MidiEvent
 {
 public:
 
-       static const int NOTE_ON = 0x90;
+       static const int NOTE_ON  = 0x90;
        static const int NOTE_OFF = 0x80;
 
        MidiEvent();
@@ -53,18 +53,28 @@ public:
        bool isNoteOnOff() const;       
        int getDelta() const;
 
-       /* getRaw
-       Returns the raw message. If 'velocity' is false, velocity byte is stripped
-       out. */
+       /* getRaw(), getRawNoVelocity()
+       Returns the raw MIDI message. If getRawNoVelocity(), the velocity value is
+       stripped off (i.e. velocity == 0). */
 
-       uint32_t getRaw(bool velocity=true) const;
+       uint32_t getRaw() const;
+       uint32_t getRawNoVelocity() const;
 
        void resetDelta();
        void setChannel(int c);
+       void setVelocity(int v);
+
+       /* fixVelocityZero()
+       According to the MIDI standard, there is a special case if the velocity is 
+       set to zero. The NOTE ON message then has the same meaning as a NOTE OFF 
+       message, switching the note off. Let's fix it. Sometime however you do want
+       a NOTE ON with velocity zero: setting velocity to 0 in MIDI action editor to
+       mute a specific event.  */
+
+       void fixVelocityZero();
 
 private:
 
-       uint32_t m_raw;
        int m_status;
        int m_channel;
        int m_note;
index 1931ed73457a128d41f343dd9e5f8e45d278fe1a..05d64e03ae4fe0aef6abf0b127361de53198f2f7 100644 (file)
@@ -50,8 +50,7 @@ namespace mixer
 {
 namespace
 {
-#define TICKSIZE 38
-
+constexpr Frame TICKSIZE = 38;
 
 float tock[TICKSIZE] = {
        0.059033,  0.117240,  0.173807,  0.227943,  0.278890,  0.325936,
@@ -63,7 +62,6 @@ float tock[TICKSIZE] = {
  -0.070862, -0.048844
 };
 
-
 float tick[TICKSIZE] = {
        0.175860,  0.341914,  0.488904,  0.608633,  0.694426,  0.741500,
        0.747229,  0.711293,    0.635697,  0.524656,  0.384362,  0.222636,
@@ -74,24 +72,25 @@ float tick[TICKSIZE] = {
        0.069639,  0.031320
 };
 
-
 AudioBuffer vChanInput;   // virtual channel for recording
 AudioBuffer vChanInToOut; // virtual channel in->out bridge (hear what you're playin)
 
-int  tickTracker, tockTracker = 0;
-bool tickPlay, tockPlay = false; // 1 = play, 0 = stop
+Frame tickTracker = 0;
+Frame tockTracker = 0;
+bool tickPlay = false;
+bool tockPlay = false;
 
 /* inputTracker
 Sample position while recording. */
 
-int inputTracker = 0;
+Frame inputTracker = 0;
 
 
 /* -------------------------------------------------------------------------- */
 
 /* computePeak */
 
-void computePeak(const AudioBuffer& buf, float& peak, unsigned frame)
+void computePeak(const AudioBuffer& buf, float& peak, Frame frame)
 {
        for (int i=0; i<buf.countChannels(); i++)
                if (buf[frame][i] > peak)
@@ -101,7 +100,6 @@ void computePeak(const AudioBuffer& buf, float& peak, unsigned frame)
 
 /* -------------------------------------------------------------------------- */
 
-
 /* lineInRec
 Records from line in. */
 
@@ -262,23 +260,15 @@ void finalizeOutput(AudioBuffer& outBuf, unsigned frame)
 
 /* -------------------------------------------------------------------------- */
 
-/* test*
-Checks if the sequencer has reached a specific point (bar, first beat or
-last frame). */
 
-void testBar(unsigned frame)
+void renderMetronome()
 {
-       if (clock::isOnBar() && metronome)
+       if (!metronome)
+               return;
+       if (clock::isOnBar() || clock::isOnFirstBeat())
                tickPlay = true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void testLastBeat()
-{
-       if (clock::isOnBeat() && metronome && !tickPlay)
+       else
+       if (clock::isOnBeat())
                tockPlay = true;
 }
 }; // {anonymous}
@@ -309,7 +299,7 @@ pthread_mutex_t mutex;
 /* -------------------------------------------------------------------------- */
 
 
-void init(int framesInSeq, int framesInBuffer)
+void init(Frame framesInSeq, Frame framesInBuffer)
 {
        /* Allocate virtual input channels. vChanInput has variable size: it depends
        on how many frames there are in sequencer. */
@@ -331,7 +321,7 @@ void init(int framesInSeq, int framesInBuffer)
 /* -------------------------------------------------------------------------- */
 
 
-void allocVirtualInput(int frames)
+void allocVirtualInput(Frame frames)
 {
        vChanInput.alloc(frames, G_MAX_IO_CHANS);
 }
@@ -380,8 +370,7 @@ int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize,
 
                        lineInRec(in, j);   // TODO - can go outside this loop
                        doQuantize(j);
-                       testBar(j);
-                       testLastBeat();
+                       renderMetronome();
                        clock::incrCurrentFrame();
                        clock::sendMIDIsync();
                }
index 4f1f341887f4fbd5a8f2065fd2aae659a8ad06bb..3a1f81ec7518ad85e939f7e8df4281622d32ebb8 100644 (file)
@@ -32,6 +32,7 @@
 #include <pthread.h>
 #include <vector>
 #include "recorder.h"
+#include "types.h"
 #include "../deps/rtaudio-mod/RtAudio.h"
 
 
@@ -44,8 +45,8 @@ namespace mixer
 {
 struct FrameEvents
 {
-       int   frameLocal;
-       int   frameGlobal;
+       Frame frameLocal;
+       Frame frameGlobal;
        bool  doQuantize;
        bool  onBar;
        bool  onFirstBeat;
@@ -53,17 +54,6 @@ struct FrameEvents
        std::vector<recorder::action*> actions;
 };
 
-enum {    // const - what to do when a fadeout ends
-       DO_STOP   = 0x01,
-       DO_MUTE   = 0x02,
-       DO_MUTE_I = 0x04
-};
-
-enum {    // const - fade types
-       FADEOUT = 0x01,
-       XFADE   = 0x02
-};
-
 extern std::vector<Channel*> channels;
 
 extern bool   recording;         // is recording something?
@@ -85,13 +75,13 @@ extern bool inToOut;
 
 extern pthread_mutex_t mutex;
 
-void init(int framesInSeq, int framesInBuffer);
+void init(Frame framesInSeq, Frame framesInBuffer);
 
 /* allocVirtualInput
 Allocates new memory for the virtual input channel. Call this whenever you 
 shrink or resize the sequencer. */
 
-void allocVirtualInput(int frames);
+void allocVirtualInput(Frame frames);
 
 void close();
 
index afcb4c9b20cedb807000cd104278b4429880366a..b3c4e809969027d7c019191e2d1d7df5fd8233d1 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef WITH_VST
 
 
+#include <cassert>
 #include <FL/Fl.H>
 #include "../utils/log.h"
 #include "../utils/time.h"
@@ -52,10 +53,13 @@ Plugin::Plugin(juce::AudioPluginInstance* plugin, double samplerate,
                id    (idGenerator++),
                bypass(false)
 {
+       using namespace juce;
+
        /* Init midiInParams. All values are empty (0x0): they will be filled during
        midi learning process. */
 
-       for (int i=0; i<plugin->getNumParameters(); i++)
+       const OwnedArray<AudioProcessorParameter>& params = plugin->getParameters();
+       for (int i=0; i<params.size(); i++)
                midiInParams.push_back(0x0);
        
        plugin->prepareToPlay(samplerate, buffersize);
@@ -86,14 +90,6 @@ void Plugin::showEditor(void* parent)
                gu_log("[Plugin::showEditor] unable to create editor!\n");
                return;
        }
-
-       /* A silly workaround on X: it seems that calling addToDesktop too fast, i.e.
-       before the X Window is fully ready screws up the plugin's event dispatcher. */
-
-#ifdef G_OS_LINUX
-       time::sleep(500);
-#endif
-
        ui->setOpaque(true);
        ui->addToDesktop(0, parent);
 }
@@ -113,7 +109,6 @@ bool Plugin::isEditorOpen() const
 
 string Plugin::getUniqueId() const
 {
-       //return plugin->getPluginDescription().fileOrIdentifier.toStdString();
        return plugin->getPluginDescription().createIdentifierString().toStdString();
 }
 
@@ -123,7 +118,7 @@ string Plugin::getUniqueId() const
 
 int Plugin::getNumParameters() const
 {
-       return plugin->getNumParameters();
+       return plugin->getParameters().size();
 }
 
 
@@ -132,7 +127,7 @@ int Plugin::getNumParameters() const
 
 float Plugin::getParameter(int paramIndex) const
 {
-       return plugin->getParameter(paramIndex);
+       return plugin->getParameters()[paramIndex]->getValue();
 }
 
 
@@ -141,7 +136,7 @@ float Plugin::getParameter(int paramIndex) const
 
 void Plugin::setParameter(int paramIndex, float value) const
 {
-       return plugin->setParameter(paramIndex, value);
+       plugin->getParameters()[paramIndex]->setValue(value);
 }
 
 
@@ -198,8 +193,8 @@ int Plugin::getId() const { return id; }
 /* -------------------------------------------------------------------------- */
 
 
-int Plugin::getEditorW() const { return ui->getWidth(); }
-int Plugin::getEditorH() const { return ui->getHeight(); }
+int Plugin::getEditorW() const { assert(ui != nullptr); return ui->getWidth(); }
+int Plugin::getEditorH() const { assert(ui != nullptr); return ui->getHeight(); }
 
 
 /* -------------------------------------------------------------------------- */
@@ -261,7 +256,7 @@ string Plugin::getProgramName(int index) const
 
 string Plugin::getParameterName(int index) const
 {
-       return plugin->getParameterName(index).toStdString();
+       return plugin->getParameters()[index]->getName(MAX_LABEL_SIZE).toStdString();
 }
 
 
@@ -270,7 +265,7 @@ string Plugin::getParameterName(int index) const
 
 string Plugin::getParameterText(int index) const
 {
-       return plugin->getParameterText(index).toStdString();
+       return plugin->getParameters()[index]->getCurrentValueAsText().toStdString();
 }
 
 
@@ -279,7 +274,7 @@ string Plugin::getParameterText(int index) const
 
 string Plugin::getParameterLabel(int index) const
 {
-       return plugin->getParameterLabel(index).toStdString();
+       return plugin->getParameters()[index]->getLabel().toStdString();
 }
 
 
@@ -288,8 +283,6 @@ string Plugin::getParameterLabel(int index) const
 
 void Plugin::closeEditor()
 {
-       if (ui == nullptr)
-               return;
        delete ui;
        ui = nullptr;
 }
index 988c20a718f01798fcc7adcce35669025b35bb5c..62633c482018994f4b199c751b20f8ef929b38cf 100644 (file)
@@ -2,8 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * plugin
- *
  * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
@@ -40,6 +38,8 @@ class Plugin
 {
 private:
 
+       static const int MAX_LABEL_SIZE = 64;
+       
        static int idGenerator;
 
        juce::AudioProcessorEditor* ui;    // gui
diff --git a/src/core/range.h b/src/core/range.h
new file mode 100644 (file)
index 0000000..296dac0
--- /dev/null
@@ -0,0 +1,57 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef G_RANGE_H
+#define G_RANGE_H
+
+
+#include <cassert>
+
+
+namespace giada
+{
+template<typename T>
+class Range
+{
+private:
+
+       T m_a;
+       T m_b;
+
+public:
+
+       Range() : m_a(0), m_b(0) {}
+       Range(T a, T b) : m_a(a), m_b(b) { assert(a < b); }
+
+       T getBegin() const  { return m_a; }
+       T getEnd() const    { return m_b; }
+       T getLength() const { return m_b - m_a; }
+};
+} // giada::
+
+
+#endif
index 7e068f4217442a87bd8b3bb0a3bbe32a23a787af..a54524d04e30b73f01d3506580bed9c436b96070 100644 (file)
@@ -54,20 +54,20 @@ Composite cmp;
 
 /* fixOverdubTruncation
 Fixes underlying action truncation when overdubbing over a longer action. I.e.:
-  Original:    |#############|
-  Overdub:     ---|#######|---
-  fix:         |#||#######|--- */
+       Original:    |#############|
+       Overdub:     ---|#######|---
+       fix:         |#||#######|--- */
 
 void fixOverdubTruncation(const Composite& comp, pthread_mutex_t* mixerMutex)
 {
-  action* next = nullptr;
-  int res = getNextAction(comp.a2.chan, comp.a1.type | comp.a2.type, comp.a2.frame,
-    &next);
-  if (res != 1 || next->type != comp.a2.type)
-    return;
-  gu_log("[recorder::fixOverdubTruncation] add truncation at frame %d, type=%d\n",
-    next->frame, next->type);
-  deleteAction(next->chan, next->frame, next->type, false, mixerMutex);
+       action* next = nullptr;
+       int res = getNextAction(comp.a2.chan, comp.a1.type | comp.a2.type, comp.a2.frame,
+               &next);
+       if (res != 1 || next->type != comp.a2.type)
+               return;
+       gu_log("[recorder::fixOverdubTruncation] add truncation at frame %d, type=%d\n",
+               next->frame, next->type);
+       deleteAction(next->chan, next->frame, next->type, false, mixerMutex);
 }
 
 }; // {anonymous}
@@ -92,7 +92,7 @@ bool sortedActions = false;
 void init()
 {
        active = false;
-  sortedActions = false;
+       sortedActions = false;
        clearAll();
 }
 
@@ -103,11 +103,12 @@ void init()
 bool canRec(Channel* ch, bool clockRunning, bool mixerRecording)
 {
        /* Can record on a channel if:
-         - recorder is on
-         - mixer is running
-         - mixer is not recording a take somewhere
-         - channel is SAMPLE type and has data in it  */
-       return active && clockRunning && !mixerRecording && ch->type == ChannelType::SAMPLE && ch->hasData();
+               - recorder is on
+               - mixer is running
+               - mixer is not recording a take somewhere
+               - channel is MIDI or SAMPLE type with data in it  */
+       return active && clockRunning && !mixerRecording && 
+              (ch->type == ChannelType::MIDI || (ch->type == ChannelType::SAMPLE && ch->hasData()));
 }
 
 
@@ -154,10 +155,10 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue)
                for (unsigned t=0; t<global.at(frameToExpand).size(); t++) {
                        action* ac = global.at(frameToExpand).at(t);
                        if (ac->chan   == index  &&
-                           ac->type   == type   &&
-                           ac->frame  == frame  &&
-                           ac->iValue == iValue &&
-                           ac->fValue == fValue)
+                                       ac->type   == type   &&
+                                       ac->frame  == frame  &&
+                                       ac->iValue == iValue &&
+                                       ac->fValue == fValue)
                                return;
                }
 
@@ -234,7 +235,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues,
        for (unsigned i=0; i<frames.size() && !found; i++) {
 
                if (frames.at(i) != frame)
-      continue;
+                       continue;
 
                        /* find the action in frame i */
 
@@ -247,20 +248,20 @@ void deleteAction(int chan, int frame, char type, bool checkValues,
                        if (checkValues)
                                doit &= (a->iValue == iValue && a->fValue == fValue);
 
-      if (!doit)
-        continue;
-
-      while (true) {
-        if (pthread_mutex_trylock(mixerMutex)) {
-          free(a);
-          global.at(i).erase(global.at(i).begin() + j);
-          pthread_mutex_unlock(mixerMutex);
-          found = true;
-          break;
-        }
-        else
-          gu_log("[recorder::deleteAction] waiting for mutex...\n");
-      }
+                       if (!doit)
+                               continue;
+
+                       while (true) {
+                               if (pthread_mutex_trylock(mixerMutex)) {
+                                       free(a);
+                                       global.at(i).erase(global.at(i).begin() + j);
+                                       pthread_mutex_unlock(mixerMutex);
+                                       found = true;
+                                       break;
+                               }
+                               else
+                                       gu_log("[recorder::deleteAction] waiting for mutex...\n");
+                       }
                }
        }
        if (found) {
@@ -278,7 +279,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues,
 
 
 void deleteActions(int chan, int frame_a, int frame_b, char type,
-  pthread_mutex_t* mixerMutex)
+       pthread_mutex_t* mixerMutex)
 {
        sortActions();
        vector<int> dels;
@@ -484,14 +485,15 @@ void shrink(int new_fpb)
 /* -------------------------------------------------------------------------- */
 
 
-bool hasActions(int chanIndex)
+bool hasActions(int chanIndex, int type)
 {
-  if (global.size() == 0)
-    return false;
+       if (global.size() == 0)
+               return false;
        for (unsigned i=0; i<global.size(); i++) {
                for (unsigned j=0; j<global.at(i).size(); j++) {
                        if (global.at(i).at(j)->chan == chanIndex)
-        return true;
+                               if (type == -1 || global.at(i).at(j)->type == type)
+                                       return true;
                }
        }
        return false;
@@ -568,14 +570,8 @@ void startOverdub(int index, char actionMask, int frame, unsigned bufferSize)
 {
        /* prepare the composite struct */
 
-       if (actionMask == G_ACTION_KEYS) {
-               cmp.a1.type = G_ACTION_KEYPRESS;
-               cmp.a2.type = G_ACTION_KEYREL;
-       }
-       else {
-               cmp.a1.type = G_ACTION_MUTEON;
-               cmp.a2.type = G_ACTION_MUTEOFF;
-       }
+       cmp.a1.type  = G_ACTION_KEYPRESS;
+       cmp.a2.type  = G_ACTION_KEYREL;
        cmp.a1.chan  = index;
        cmp.a2.chan  = index;
        cmp.a1.frame = frame;
@@ -610,14 +606,14 @@ void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t* mixerMutex)
        bool nullLoop = false;
 
        /* Check for ring loops or null loops. Ring loop: a composite action with
-  key_press at frame N and key_release at frame M, with M <= N.
-  Null loop: a composite action that begins and ends on the very same frame,
-  i.e. with 0 size. Very unlikely.
-  If ring loop: record the last action at the end of the sequencer (that
-  is 'totalFrames').
-  If null loop: remove previous action and do nothing. Also make sure to avoid
-  underlying action truncation, if the null loop occurs inside a composite
-  action. */
+       key_press at frame N and key_release at frame M, with M <= N.
+       Null loop: a composite action that begins and ends on the very same frame,
+       i.e. with 0 size. Very unlikely.
+       If ring loop: record the last action at the end of the sequencer (that
+       is 'totalFrames').
+       If null loop: remove previous action and do nothing. Also make sure to avoid
+       underlying action truncation, if the null loop occurs inside a composite
+       action. */
 
        if (cmp.a2.frame < cmp.a1.frame) {  // ring loop
                ringLoop = true;
@@ -629,25 +625,25 @@ void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t* mixerMutex)
                nullLoop = true;
                gu_log("[recorder::stopOverdub] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
                deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false, mixerMutex); // false == don't check values
-    fixOverdubTruncation(cmp, mixerMutex);
-  }
+               fixOverdubTruncation(cmp, mixerMutex);
+       }
 
-  if (nullLoop)
-    return;
+       if (nullLoop)
+               return;
 
        /* Remove any nested action between keypress----keyrel. */
 
        deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type, mixerMutex);
        deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type, mixerMutex);
 
-  if (ringLoop)
-    return;
+       if (ringLoop)
+               return;
 
-  /* Record second part of the composite action. Also make sure to avoid
-  underlying action truncation, if keyrel happens inside a composite action. */
+       /* Record second part of the composite action. Also make sure to avoid
+       underlying action truncation, if keyrel happens inside a composite action. */
 
        rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
-  fixOverdubTruncation(cmp, mixerMutex);
+       fixOverdubTruncation(cmp, mixerMutex);
 }
 
 
@@ -670,6 +666,7 @@ vector<action*> getActionsOnFrame(int frame)
 
 void forEachAction(std::function<void(const action*)> f)
 {
+
        for (const vector<action*> actions : recorder::global)
                for (const action* action : actions)
                        f(action);
index cdbcc2c5706d8dd1cb084b7f0338be93aa18d925..d62017b8c6ce78e0bfbc26314c4a6e5e51808e5c 100644 (file)
@@ -92,9 +92,9 @@ void init();
 
 /* hasActions
 Checks if the channel has at least one action recorded. Used after an
-action deletion. */
+action deletion. Type != -1: check if channel has actions of type 'type'.*/
 
-bool hasActions(int chanIndex);
+bool hasActions(int chanIndex, int type=-1);
 
 /* canRec
  * can a channel rec an action? Call this one BEFORE rec(). */
index 0ce44f6ea253d22806d1dc784ee863511d03c154..8139a7c55e850e6a42b04c99ad9d9c02423f8755 100644 (file)
@@ -182,12 +182,6 @@ void SampleChannel::recordStop()
 }
 
 
-void SampleChannel::recordMute()
-{
-       sampleChannelRec::recordMute(this);
-}
-
-
 /* -------------------------------------------------------------------------- */
 
 
@@ -220,9 +214,9 @@ void SampleChannel::stopInputRec(int globalFrame)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setMute(bool value, EventType eventType)
+void SampleChannel::setMute(bool value)
 {
-       sampleChannelProc::setMute(this, value, eventType);
+       sampleChannelProc::setMute(this, value);
 }
 
 
index 87aca99d73bacde4962a14f364b4bd7a8889da86..857e8e1cdc316f4c71fba410bdff83deb6118614 100644 (file)
@@ -60,8 +60,7 @@ public:
        bool recordStart(bool canQuantize) override;
        bool recordKill() override;
        void recordStop() override;
-       void recordMute() override;
-       void setMute(bool value, giada::EventType eventType) override;
+       void setMute(bool value) override;
        void startReadingActions(bool treatRecsAsLoops, bool recsStopOnChanHalt) override;
        void stopReadingActions(bool running, bool treatRecsAsLoops, 
                bool recsStopOnChanHalt) override;
index 546adf78bb07459118dae41a03109c703af73f85..aa23584f467665497576247b7f03b40ed7c31963 100644 (file)
 
 #include <cassert>
 #include "../utils/math.h"
+#include "const.h"
 #include "pluginHost.h"
 #include "sampleChannel.h"
 #include "sampleChannelProc.h"
-#include "clock.h"
 
 
 namespace giada {
@@ -42,7 +42,6 @@ namespace
 void rewind_(SampleChannel* ch, int localFrame)
 {
        ch->tracker = ch->begin;
-       ch->mute_i  = false;
        ch->qWait   = false;  // Was in qWait mode? Reset occured, no more qWait now.
 
        /* On rewind, if channel is playing fill again buffer to create something like 
@@ -210,7 +209,7 @@ void processData_(SampleChannel* ch, m::AudioBuffer& out, const m::AudioBuffer&
        for (int i=0; i<out.countFrames(); i++) {
                if (running)
                        ch->calcVolumeEnvelope();
-               if (!ch->mute && !ch->mute_i)
+               if (!ch->mute)
                        for (int j=0; j<out.countChannels(); j++)
                                out[i][j] += ch->buffer[i][j] * ch->volume * ch->volume_i * ch->calcPanning(j) * ch->boost;     
        }
@@ -354,9 +353,9 @@ void rewindBySeq(SampleChannel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void setMute(SampleChannel* ch, bool value, EventType eventType)
+void setMute(SampleChannel* ch, bool value)
 {
-       eventType == EventType::MANUAL ? ch->mute = value : ch->mute_i = value;
+       ch->mute = value;
        ch->sendMidiLmute();
 }
 
@@ -369,7 +368,7 @@ void start(SampleChannel* ch, int localFrame, bool doQuantize, int velocity)
        /* For one-shot modes, velocity drives the internal volume. */
        if (velocity != 0) {
                if (ch->isAnySingleMode() && ch->midiInVeloAsVol)
-                       ch->volume_i = u::math::map<float>(velocity, 0.0f, 127.0f, 0.0f, 1.0f);         
+                       ch->volume_i = u::math::map<int, float>(velocity, 0, G_MAX_VELOCITY, 0.0, 1.0);         
        }
 
        switch (ch->status)     {
index 341cbfd2dc1279356179bb944c82d15cb41d0e60..0c95a69511b1321f66293a098f34f32c675bf357 100644 (file)
@@ -84,7 +84,7 @@ actions from Recorder. */
 
 void start(SampleChannel* ch, int localFrame, bool doQuantize, int velocity);
 
-void setMute(SampleChannel* ch, bool value, EventType eventType);
+void setMute(SampleChannel* ch, bool value);
 }}};
 
 
index ec28bb955e8f6519038f562b3e037e3301c134e3..91db54165395dd437a185d03b6539d67b43d7d05 100644 (file)
@@ -25,6 +25,7 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include "const.h"
 #include "conf.h"
 #include "clock.h"
@@ -90,8 +91,8 @@ void calcVolumeEnv_(SampleChannel* ch, int globalFrame)
         * is not found. */
 
        res = recorder::getAction(ch->index, G_ACTION_VOLUME, globalFrame, &a0);
-       if (res == 0)
-               return;
+
+       assert(res != 0);
 
        /* get the action next to this one.
         * res == -1: a1 not found, this is the last one. Rewind the search
@@ -99,10 +100,11 @@ void calcVolumeEnv_(SampleChannel* ch, int globalFrame)
         * res == -2 G_ACTION_VOLUME not found. This should never happen */
 
        res = recorder::getNextAction(ch->index, G_ACTION_VOLUME, globalFrame, &a1);
-
        if (res == -1)
                res = recorder::getAction(ch->index, G_ACTION_VOLUME, 0, &a1);
 
+       assert(res != -2);
+
        ch->volume_i = a0->fValue;
        ch->volume_d = ((a1->fValue - a0->fValue) / (a1->frame - a0->frame)) * 1.003f;
 }
@@ -136,12 +138,6 @@ void parseAction_(SampleChannel* ch, const recorder::action* a, int localFrame,
                        if (ch->isAnySingleMode())
                                ch->kill(localFrame);
                        break;
-               case G_ACTION_MUTEON:
-                       ch->setMute(true, EventType::AUTO);
-                       break;
-               case G_ACTION_MUTEOFF:
-                       ch->setMute(false, EventType::AUTO);
-                       break;
                case G_ACTION_VOLUME:
                        calcVolumeEnv_(ch, globalFrame);
                        break;
@@ -204,24 +200,6 @@ void parseEvents(SampleChannel* ch, mixer::FrameEvents fe)
 /* -------------------------------------------------------------------------- */
 
 
-void recordMute(SampleChannel* ch)
-{
-       if (recorderCanRec_(ch)) {
-               if (!ch->mute) {
-                       recorder::startOverdub(ch->index, G_ACTION_MUTES, clock::getCurrentFrame(),
-                               kernelAudio::getRealBufSize());
-                       ch->readActions = false;   // don't read actions while overdubbing
-               }
-               else
-                recorder::stopOverdub(clock::getCurrentFrame(), clock::getFramesInLoop(),
-                       &mixer::mutex);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 bool recordStart(SampleChannel* ch, bool canQuantize)
 {
        /* Record a 'start' event if the quantizer is off, otherwise let mixer to 
index 6fe5d48e44461a6778650917ac9f781f9d6b1066..6694b2e8f0c9d8b80be89523e11ec393909341bf 100644 (file)
@@ -55,8 +55,6 @@ Ends overdub mode SINGLE_PRESS channels. */
 
 void recordStop(SampleChannel* ch);
 
-void recordMute(SampleChannel* ch);
-
 /* setReadActions
 If enabled (v == true), Recorder will read actions from channel 'ch'. If 
 recsStopOnChanHalt == true and v == false, will also kill the channel. */
index d83fd3c2c2e12cde9e1e7b100ff2d37a2864d8ca..4754a1006ee49c40afb96792d924d6cfc11fcb31 100644 (file)
 
 namespace giada
 {
+using Pixel = int;
+using Frame = int;
+
+
 enum class ChannelType : int 
 {
        SAMPLE = 1, MIDI
index 95123080fc2f5722f1ddbac513d867b9f9e21c21..1276dc613b3cf29dac9cd9fe8a6d4c3ff8c716d0 100644 (file)
@@ -2,8 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * wave
- *
  * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
index 5ea0e71bf92f673aba52b7e359d11429e0200d83..f285bf305752179478ff01137d69e2ac6373cda0 100644 (file)
@@ -2,8 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * wave
- *
  * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
index e0a90bde05515358d30ac390ff16ba8082464b20..06ac502f0067a114a72c840792dc921cb4bad117 100644 (file)
Binary files a/src/ext/giada.ico and b/src/ext/giada.ico differ
index cdfe12d690fa0d512636131f31d2fda5fa094450..aaa805cb486c6c2d29a7c654ac2f97dfd06a34e4 100644 (file)
@@ -271,7 +271,7 @@ void setPanning(SampleChannel* ch, float val)
 
 void toggleMute(Channel* ch, bool gui)
 {
-       ch->setMute(!ch->mute, EventType::MANUAL);
+       ch->setMute(!ch->mute);
        if (!gui) {
                Fl::lock();
                ch->guiChannel->mute->value(ch->mute);
index d9788030f2260002585da2fd21511b3c5011d7c5..767473f47da82c224cfab8cd8953e3277c0b4190 100644 (file)
@@ -61,10 +61,8 @@ namespace io
 void keyPress(Channel* ch, bool ctrl, bool shift, int velocity)
 {
        /* Everything occurs on frame 0 here: they are all user-generated events. */
-       if (ctrl) {
-               ch->recordMute();
+       if (ctrl)
                c::channel::toggleMute(ch);
-       }
        else
        if (shift) {
                if (ch->recordKill())
index f193285a3230aa35cc143c196a7b02e41bccde28..47e5b56481d1639022d609c7c22318602538d692 100644 (file)
@@ -25,6 +25,7 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include "../gui/dialogs/gd_warnings.h"
 #include "../gui/elems/mainWindow/keyboard/channel.h"
 #include "../gui/elems/mainWindow/keyboard/sampleChannel.h"
@@ -33,6 +34,9 @@
 #include "../core/kernelMidi.h"
 #include "../core/channel.h"
 #include "../core/recorder.h"
+#include "../core/mixer.h"
+#include "../core/sampleChannel.h"
+#include "../core/midiChannel.h"
 #include "../utils/gui.h"
 #include "../utils/log.h"
 #include "recorder.h"
@@ -48,17 +52,21 @@ namespace recorder
 {
 namespace
 {
-void updateChannel(geChannel* gch)
+void updateChannel(geChannel* gch, bool refreshActionEditor=true)
 {
        gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
-       if (gch->ch->type == ChannelType::SAMPLE && !gch->ch->hasActions)
-               static_cast<geSampleChannel*>(gch)->hideActionButton();
-       /* TODO - set mute=false */
-       gu_refreshActionEditor(); // refresh a.editor window, it could be open
+       if (gch->ch->type == ChannelType::SAMPLE) {
+               geSampleChannel* gsch = static_cast<geSampleChannel*>(gch);
+               gsch->ch->hasActions ? gsch->showActionButton() : gsch->hideActionButton();
+       }
+       if (refreshActionEditor)
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
 }
-}; // {namespace}
+}; // {anonymous}
 
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 
@@ -98,22 +106,41 @@ void clearStartStopActions(geChannel* gch)
 /* -------------------------------------------------------------------------- */
 
 
-void clearMuteActions(geChannel* gch)
+bool midiActionCanFit(int chan, int note, int frame_a, int frame_b)
 {
-       if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
-               return;
-       m::recorder::clearAction(gch->ch->index, G_ACTION_MUTEON | G_ACTION_MUTEOFF);
-       updateChannel(gch);
+       namespace mr = m::recorder;
+
+       /* TODO - This is insane, to say the least. Let's wait for recorder refactoring... */
+
+       vector<mr::Composite> comps = getMidiActions(chan);
+       for (mr::Composite c : comps)
+    if (frame_b >= c.a1.frame && c.a2.frame >= frame_a && m::MidiEvent(c.a1.iValue).getNote() == note)
+                       return false;
+       return true;
+}
+
+
+bool sampleActionCanFit(const SampleChannel* ch, int frame_a, int frame_b)
+{
+       namespace mr = m::recorder;
+
+       /* TODO - Even more insanity... Let's wait for recorder refactoring... */
+
+       vector<mr::Composite> comps = getSampleActions(ch);
+       for (mr::Composite c : comps)
+    if (frame_b >= c.a1.frame && c.a2.frame >= frame_a)
+                       return false;
+       return true;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void recordMidiAction(int chan, int note, int frame_a, int frame_b)
+void recordMidiAction(int chan, int note, int velocity, int frame_a, int frame_b)
 {
        if (frame_b == 0)
-               frame_b = frame_a + G_DEFAULT_MIDI_ACTION_SIZE;
+               frame_b = frame_a + G_DEFAULT_ACTION_SIZE;
 
        /* Avoid frame overflow. */
 
@@ -123,33 +150,207 @@ void recordMidiAction(int chan, int note, int frame_a, int frame_b)
                frame_a -= overflow;
        }
 
-       /* Prepare MIDI events, with maximum velocity (0x3F) for now. */
+       /* Prepare MIDI events. Due to some nasty restrictions on the ancient Recorder,
+       checks for overlapping are done by the caller. TODO ... */
 
-       m::MidiEvent event_a = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, 0x3F);
-       m::MidiEvent event_b = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, 0x3F);
+       m::MidiEvent event_a = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, velocity);
+       m::MidiEvent event_b = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, velocity);
 
-       /* Avoid overlapping actions. Find the next action past frame_a and compare 
-       its frame: if smaller than frame_b, an overlap occurs. Shrink the new action
-       accordingly. */
+       m::recorder::rec(chan, G_ACTION_MIDI, frame_a, event_a.getRaw());
+       m::recorder::rec(chan, G_ACTION_MIDI, frame_b, event_b.getRaw());               
+}
 
-       m::recorder::action* next = nullptr;
-       m::recorder::getNextAction(chan, G_ACTION_MIDI, frame_a, &next, event_a.getRaw(), 
-               0x0000FF00);
 
-       if (next != nullptr && next->frame <= frame_b) {
-               frame_b = next->frame - 2;
-               gu_log("[recorder::recordMidiAction] Shrink new action, due to overlap\n");
+/* -------------------------------------------------------------------------- */
+
+
+void deleteMidiAction(MidiChannel* ch, m::recorder::action a1, m::recorder::action a2)
+{
+       m::recorder::deleteAction(ch->index, a1.frame, G_ACTION_MIDI, true, 
+               &m::mixer::mutex, a1.iValue, 0.0);
+       
+       /* If action 1 is not orphaned, send a note-off first in case we are deleting 
+       it in a middle of a key_on/key_off sequence. Conversely, orphaned actions
+       should not play, so no need to fire the note-off. */
+       
+       if (a2.frame != -1) {
+               ch->sendMidi(a2.iValue);
+               m::recorder::deleteAction(ch->index, a2.frame, G_ACTION_MIDI, true, 
+                       &m::mixer::mutex, a2.iValue, 0.0);
        }
 
-       m::recorder::rec(chan, G_ACTION_MIDI, frame_a, event_a.getRaw());
-       m::recorder::rec(chan, G_ACTION_MIDI, frame_b, event_b.getRaw());               
+       ch->hasActions = m::recorder::hasActions(ch->index);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void recordSampleAction(SampleChannel* ch, int type, int frame_a, int frame_b)
+{
+       if (ch->mode == ChannelMode::SINGLE_PRESS) {
+               m::recorder::rec(ch->index, G_ACTION_KEYPRESS, frame_a);
+               m::recorder::rec(ch->index, G_ACTION_KEYREL, frame_b == 0 ? frame_a + G_DEFAULT_ACTION_SIZE : frame_b);
+       }
+       else
+               m::recorder::rec(ch->index, type, frame_a);
+
+       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void recordEnvelopeAction(Channel* ch, int type, int frame, float fValue)
+{
+       namespace mr = m::recorder;
+
+       if (!mr::hasActions(ch->index, type)) {  // First action ever? Add actions at boundaries.
+               mr::rec(ch->index, type, 0, 0, 1.0);    
+               mr::rec(ch->index, type, m::clock::getFramesInLoop() - 1, 0, 1.0);      
+       }
+       mr::rec(ch->index, type, frame, 0, fValue);
+
+       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void deleteEnvelopeAction(Channel* ch, m::recorder::action a, bool moved)
+{
+       namespace mr = m::recorder;
+
+       /* Deleting first or last action: clear everything. Otherwise delete the 
+       selected action only. */
+
+       if (!moved && (a.frame == 0 || a.frame == m::clock::getFramesInLoop() - 1))
+               mr::clearAction(ch->index, a.type);
+       else
+               mr::deleteAction(ch->index, a.frame, a.type, false, &m::mixer::mutex);
+
+       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void deleteSampleAction(SampleChannel* ch, m::recorder::action a1, 
+       m::recorder::action a2)
+{
+       namespace mr = m::recorder;
+
+       /* if SINGLE_PRESS delete both the keypress and the keyrelease pair. */
+
+       if (ch->mode == ChannelMode::SINGLE_PRESS) {
+               mr::deleteAction(ch->index, a1.frame, G_ACTION_KEYPRESS, false, &m::mixer::mutex);
+               mr::deleteAction(ch->index, a2.frame, G_ACTION_KEYREL, false, &m::mixer::mutex);
+       }
+       else
+               mr::deleteAction(ch->index, a1.frame, a1.type, false, &m::mixer::mutex);
+
+  updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+vector<m::recorder::Composite> getSampleActions(const SampleChannel* ch)
+{
+       namespace mr = m::recorder;
+
+       vector<mr::Composite> out;
+
+       mr::sortActions();
+       mr::forEachAction([&](const mr::action* a1)
+       {
+               /* Exclude:
+               - actions beyond clock::getFramesInLoop();
+               - actions that don't belong to channel ch;
+               - actions != G_ACTION_KEYPRESS, G_ACTION_KEYREL or G_ACTION_KILL;
+               - G_ACTION_KEYREL actions in a SINGLE_PRESS context. */
+
+               if (a1->frame > m::clock::getFramesInLoop() || 
+                         a1->chan != ch->index                   || 
+                         a1->type & ~(G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL) || 
+                         (ch->mode == ChannelMode::SINGLE_PRESS && a1->type == G_ACTION_KEYREL))
+                       return;
+
+               mr::Composite cmp; 
+               cmp.a1 = *a1;
+               cmp.a2.frame = -1;
+
+               /* If SINGLE_PRESS mode and the current action is G_ACTION_KEYPRESS, let's
+               fetch the corresponding G_ACTION_KEYREL. */
+
+               if (ch->mode == ChannelMode::SINGLE_PRESS && a1->type == G_ACTION_KEYPRESS) {
+                       m::recorder::action* a2 = nullptr;
+                       mr::getNextAction(ch->index, G_ACTION_KEYREL, a1->frame, &a2);
+                       if (a2 != nullptr)
+                               cmp.a2 = *a2;
+               }
+
+               out.push_back(cmp);
+       });
+
+       return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+vector<m::recorder::action> getEnvelopeActions(const Channel* ch, int type)
+{
+       namespace mr = m::recorder;
+
+       vector<mr::action> out;
+
+       mr::sortActions();
+       mr::forEachAction([&](const mr::action* a)
+       {
+               /* Exclude:
+               - actions beyond clock::getFramesInLoop();
+               - actions that don't belong to channel ch;
+               - actions with wrong type. */
+
+               if (a->frame > m::clock::getFramesInLoop() || 
+                         a->chan != ch->index                   || 
+                         a->type != type)
+                       return;
+
+               out.push_back(*a);
+       });
+
+       return out;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-vector<m::recorder::Composite> getMidiActions(int chan, int frameLimit)
+void setVelocity(const Channel* ch, m::recorder::action a, int value)
+{
+       /* TODO - this is super ugly: delete the action and add a new one with the
+       modified values. This shit will go away as soon as we'll refactor m::recorder
+       for good. */
+
+       m::MidiEvent event = m::MidiEvent(a.iValue);
+       event.setVelocity(value);
+
+       m::recorder::deleteAction(ch->index, a.frame, G_ACTION_MIDI, true, 
+               &m::mixer::mutex, a.iValue, 0.0);
+       m::recorder::rec(ch->index, G_ACTION_MIDI, a.frame, event.getRaw());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+vector<m::recorder::Composite> getMidiActions(int chan)
 {
        vector<m::recorder::Composite> out;
 
@@ -157,7 +358,7 @@ vector<m::recorder::Composite> getMidiActions(int chan, int frameLimit)
 
        for (unsigned i=0; i<m::recorder::frames.size(); i++) {
 
-               if (m::recorder::frames.at(i) > frameLimit)
+               if (m::recorder::frames.at(i) > m::clock::getFramesInLoop())
                        continue;
 
                for (unsigned j=0; j<m::recorder::global.at(i).size(); j++) {
@@ -187,10 +388,9 @@ vector<m::recorder::Composite> getMidiActions(int chan, int frameLimit)
                        note of a1 and random velocity: we don't care about it (and so we mask it
                        with 0x0000FF00). */
 
-                       m::MidiEvent a2midi(m::MidiEvent::NOTE_OFF, a1midi.getNote(), 0x0);
-
                        m::recorder::getNextAction(chan, G_ACTION_MIDI, a1->frame, &a2, 
-                               a2midi.getRaw(), 0x0000FF00);
+                               m::MidiEvent(m::MidiEvent::NOTE_OFF, a1midi.getNote(), 0x0).getRaw(), 
+                               0x0000FF00);
 
                        /* If action 2 has been found, add it to the composite duo. Otherwise
                        set the action 2 frame to -1: it should be intended as "orphaned". */
index ab417db278d273be87bdef6b0b77abb42730a31f..1bf4a4044feb4045d9fe5cf3fec9a14327ebec9e 100644 (file)
@@ -33,6 +33,8 @@
 #include "../core/recorder.h"
 
 
+class SampleChannel;
+class MidiChannel;
 class geChannel;
 
 
@@ -41,22 +43,50 @@ namespace c     {
 namespace recorder 
 {
 void clearAllActions(geChannel* gch);
-void clearMuteActions(geChannel* gch);
 void clearVolumeActions(geChannel* gch);
 void clearStartStopActions(geChannel* gch);
 
+
+
+/* MOVE ALL THESE FUNCTIONS TO c::actionEditor*/
+
+
+bool midiActionCanFit(int chan, int note, int frame_a, int frame_b);
+bool sampleActionCanFit(const SampleChannel* ch, int frame_a, int frame_b);
+
 /* recordMidiAction
 Records a new MIDI action at frame_a. If frame_b == 0, uses the default action
 size. This function is designed for the Piano Roll (not for live recording). */
 
-void recordMidiAction(int chan, int note, int frame_a, int frame_b=0);
+void recordMidiAction(int chan, int note, int velocity, int frame_a, int frame_b=0);
+
+void recordEnvelopeAction(Channel* ch, int type, int frame, float fValue);
+
+void recordSampleAction(SampleChannel* ch, int type, int frame_a, int frame_b=0);
+
+void setVelocity(const Channel* ch, m::recorder::action a, int value);
 
 /* getMidiActions
 Returns a list of Composite actions, ready to be displayed in a MIDI note
 editor as pairs of NoteOn+NoteOff. */
 
-std::vector<giada::m::recorder::Composite> getMidiActions(int channel, 
-       int frameLimit);
+std::vector<m::recorder::Composite> getMidiActions(int channel);
+
+std::vector<m::recorder::action> getEnvelopeActions(const Channel* ch, int type);
+
+/* getSampleActions
+Returns a list of Composite actions, ready to be displayed in a Sample Action
+Editor. If actions are not keypress+keyrelease combos, the second action in
+the Composite struct if left empty (with action2.frame = -1). */
+
+std::vector<m::recorder::Composite> getSampleActions(const SampleChannel* ch);
+
+void deleteMidiAction(MidiChannel* ch, m::recorder::action a1, m::recorder::action a2);
+
+void deleteSampleAction(SampleChannel* ch, m::recorder::action a1, 
+       m::recorder::action a2);
+
+void deleteEnvelopeAction(Channel* ch, m::recorder::action a, bool moved);
 
 }}} // giada::c::recorder::
 
index 79f7996cd12be64e09cc2b973d57c4ab3caf68a4..dfe503a6b440a1f040fd2b07871b3f0279d88de9 100644 (file)
@@ -59,7 +59,7 @@ gdAbout::gdAbout()
 
        set_modal();
 
-       logo  = new geBox(8, 10, 324, 86);
+       logo  = new geBox(8, 20, 324, 86);
        text  = new geBox(8, 120, 324, 145);
        close = new geButton(252, h()-28, 80, 20, "Close");
 #ifdef WITH_VST
diff --git a/src/gui/dialogs/actionEditor/baseActionEditor.cpp b/src/gui/dialogs/actionEditor/baseActionEditor.cpp
new file mode 100644 (file)
index 0000000..b85a30e
--- /dev/null
@@ -0,0 +1,212 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <cassert>
+#include <string>
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include "../../../utils/gui.h"
+#include "../../../utils/string.h"
+#include "../../../core/conf.h"
+#include "../../../core/const.h"
+#include "../../../core/clock.h"
+#include "../../../core/channel.h"
+#include "../../elems/actionEditor/gridTool.h"
+#include "../../elems/basics/scroll.h"
+#include "../../elems/basics/choice.h"
+#include "baseActionEditor.h"
+
+
+using std::string;
+
+
+namespace giada {
+namespace v
+{
+gdBaseActionEditor::gdBaseActionEditor(Channel* ch)
+:      gdWindow (640, 284),
+       ch       (ch),
+       ratio    (G_DEFAULT_ZOOM_RATIO)
+{
+       using namespace giada::m;
+
+       if (conf::actionEditorW) {
+               resize(conf::actionEditorX, conf::actionEditorY, conf::actionEditorW, conf::actionEditorH);
+               ratio = conf::actionEditorZoom;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdBaseActionEditor::~gdBaseActionEditor()
+{
+       using namespace giada::m;
+
+       conf::actionEditorX = x();
+       conf::actionEditorY = y();
+       conf::actionEditorW = w();
+       conf::actionEditorH = h();
+       conf::actionEditorZoom = ratio;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::cb_zoomIn(Fl_Widget *w, void *p)  { ((gdBaseActionEditor*)p)->zoomIn(); }
+void gdBaseActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdBaseActionEditor*)p)->zoomOut(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::computeWidth()
+{
+       fullWidth = frameToPixel(m::clock::getFramesInSeq());
+       loopWidth = frameToPixel(m::clock::getFramesInLoop());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+Pixel gdBaseActionEditor::frameToPixel(Frame f) const
+{
+       return f / ratio;
+}
+
+
+Frame gdBaseActionEditor::pixelToFrame(Pixel p, bool snap) const
+{
+       return snap ? gridTool->getSnapFrame(p * ratio) : p * ratio;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::zoomIn()
+{
+       if (ratio / 2 > MIN_RATIO) {
+               ratio /= 2;
+               rebuild();
+               centerViewportIn();
+               redraw();
+       }
+       else
+               ratio = MIN_RATIO;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::zoomOut()
+{
+       if (ratio * 2 < MAX_RATIO) {
+               ratio *= 2;
+               rebuild();
+               centerViewportOut();
+               redraw();
+       }
+       else
+               ratio = MAX_RATIO;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::centerViewportIn()
+{
+       Pixel sx = Fl::event_x() + (viewport->xposition() * 2);
+       viewport->scroll_to(sx, viewport->yposition()); 
+}
+
+
+void gdBaseActionEditor::centerViewportOut()
+{
+       Pixel sx = -((Fl::event_x() + viewport->xposition()) / 2) + viewport->xposition();
+       if (sx < 0) sx = 0;
+       viewport->scroll_to(sx, viewport->yposition());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gdBaseActionEditor::getActionType() const
+{
+       if (actionType->value() == 0)
+               return G_ACTION_KEYPRESS;
+       else
+       if (actionType->value() == 1)
+               return G_ACTION_KEYREL;
+       else
+       if (actionType->value() == 2)
+               return G_ACTION_KILL;
+
+       assert(false);
+       return -1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBaseActionEditor::prepareWindow()
+{
+       gu_setFavicon(this);
+
+       string l = "Action Editor";
+       if (ch->name != "") l += " - " + ch->name;
+       copy_label(l.c_str());
+
+       set_non_modal();
+       size_range(640, 284);
+       resizable(viewport);
+
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gdBaseActionEditor::handle(int e)
+{
+       switch (e) {
+               case FL_MOUSEWHEEL:
+                       Fl::event_dy() == -1 ? zoomIn() : zoomOut();
+                       return 1;
+               default:
+                       return Fl_Group::handle(e);
+       }
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/dialogs/actionEditor/baseActionEditor.h b/src/gui/dialogs/actionEditor/baseActionEditor.h
new file mode 100644 (file)
index 0000000..1b35d79
--- /dev/null
@@ -0,0 +1,105 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_BASE_ACTION_EDITOR_H
+#define GD_BASE_ACTION_EDITOR_H
+
+
+#include "../../../core/types.h"
+#include "../window.h"
+
+
+class Channel;
+class geChoice;
+class geButton;
+class geScroll;
+
+
+namespace giada {
+namespace v
+{
+class geGridTool;
+
+
+class gdBaseActionEditor : public gdWindow
+{
+protected:
+
+       static constexpr Pixel RESIZER_BAR_H = 20;
+       static constexpr Pixel MIN_WIDGET_H  = 10;
+       static constexpr float MIN_RATIO     = 25.0f;
+       static constexpr float MAX_RATIO     = 40000.0f;
+
+       gdBaseActionEditor(Channel* ch);
+
+       void zoomIn();
+       void zoomOut();
+       static void cb_zoomIn(Fl_Widget* w, void* p);
+       static void cb_zoomOut(Fl_Widget* w, void* p);
+       
+       /* computeWidth
+  Computes total width, in pixel. */
+
+       void computeWidth();
+
+       void centerViewportIn();
+       void centerViewportOut();
+
+       void prepareWindow();
+
+public:
+
+       virtual ~gdBaseActionEditor();
+
+       /* rebuild
+       Forces all internal widgets to rebuild themselves. Used when refreshing the
+       whole Action Editor window. */
+       
+       virtual void rebuild() = 0;
+
+       int handle(int e) override;
+
+       Pixel frameToPixel(Frame f) const;
+       Frame pixelToFrame(Pixel p, bool snap=true) const;
+       int getActionType() const;
+
+       geChoice*   actionType;
+       geGridTool* gridTool;
+       geButton*   zoomInBtn;
+       geButton*   zoomOutBtn;
+       geScroll*   viewport;       // widget container
+
+       Channel* ch;
+
+       float ratio;
+       Pixel fullWidth;   // Full widgets width, i.e. scaled-down full sequencer
+       Pixel loopWidth;         // Loop width, i.e. scaled-down sequencer range
+};
+}} // giada::v::
+
+
+#endif
diff --git a/src/gui/dialogs/actionEditor/midiActionEditor.cpp b/src/gui/dialogs/actionEditor/midiActionEditor.cpp
new file mode 100644 (file)
index 0000000..ab65cef
--- /dev/null
@@ -0,0 +1,95 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <string>
+#include "../../../core/graphics.h"
+#include "../../../core/midiChannel.h"
+#include "../../elems/basics/scroll.h"
+#include "../../elems/basics/button.h"
+#include "../../elems/basics/resizerBar.h"
+#include "../../elems/basics/box.h"
+#include "../../elems/actionEditor/noteEditor.h"
+#include "../../elems/actionEditor/velocityEditor.h"
+#include "../../elems/actionEditor/pianoRoll.h"
+#include "../../elems/actionEditor/gridTool.h"
+#include "midiActionEditor.h"
+
+
+using std::string;
+
+
+namespace giada {
+namespace v
+{
+gdMidiActionEditor::gdMidiActionEditor(MidiChannel* ch)
+: gdBaseActionEditor(ch)
+{
+       computeWidth();
+
+       Fl_Group* upperArea = new Fl_Group(8, 8, w()-16, 20);
+
+       upperArea->begin();
+
+               gridTool = new geGridTool(8, 8);
+
+               geBox *b1  = new geBox(gridTool->x()+gridTool->w()+4, 8, 300, 20);    // padding actionType - zoomButtons
+               zoomInBtn  = new geButton(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+               zoomOutBtn = new geButton(w()-8-20,   8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
+       
+       upperArea->end();
+       upperArea->resizable(b1);
+
+       zoomInBtn->callback(cb_zoomIn, (void*)this);
+       zoomOutBtn->callback(cb_zoomOut, (void*)this);
+
+       /* Main viewport: contains all widgets. */
+
+       viewport = new geScroll(8, 36, w()-16, h()-44);
+
+       ne = new geNoteEditor(viewport->x(), viewport->y(), this);
+       viewport->add(ne);
+       viewport->add(new geResizerBar(ne->x(), ne->y()+ne->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       
+       ve = new geVelocityEditor(viewport->x(), ne->y()+ne->h()+RESIZER_BAR_H, ch);
+       viewport->add(ve);
+       viewport->add(new geResizerBar(ve->x(), ve->y()+ve->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+
+       end();
+       prepareWindow();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiActionEditor::rebuild()
+{
+       computeWidth();
+       ne->rebuild();
+       ve->rebuild();
+}
+}} // giada::v::
diff --git a/src/gui/dialogs/actionEditor/midiActionEditor.h b/src/gui/dialogs/actionEditor/midiActionEditor.h
new file mode 100644 (file)
index 0000000..15da033
--- /dev/null
@@ -0,0 +1,61 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_MIDI_ACTION_EDITOR_H
+#define GD_MIDI_ACTION_EDITOR_H
+
+
+#include "baseActionEditor.h"
+
+
+class MidiChannel;
+
+
+namespace giada {
+namespace v
+{
+class geNoteEditor;
+class geVelocityEditor;
+
+
+class gdMidiActionEditor : public gdBaseActionEditor
+{
+private:
+
+       geNoteEditor*     ne;
+       geVelocityEditor* ve;
+
+public:
+
+       gdMidiActionEditor(MidiChannel* ch);
+
+       void rebuild() override;
+};
+}} // giada::v::
+
+
+#endif
diff --git a/src/gui/dialogs/actionEditor/sampleActionEditor.cpp b/src/gui/dialogs/actionEditor/sampleActionEditor.cpp
new file mode 100644 (file)
index 0000000..2f2e268
--- /dev/null
@@ -0,0 +1,118 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <string>
+#include "../../../core/const.h"
+#include "../../../core/graphics.h"
+#include "../../../core/sampleChannel.h"
+#include "../../elems/basics/scroll.h"
+#include "../../elems/basics/button.h"
+#include "../../elems/basics/resizerBar.h"
+#include "../../elems/basics/choice.h"
+#include "../../elems/basics/box.h"
+#include "../../elems/actionEditor/sampleActionEditor.h"
+#include "../../elems/actionEditor/envelopeEditor.h"
+#include "../../elems/actionEditor/gridTool.h"
+#include "sampleActionEditor.h"
+
+
+using std::string;
+
+
+namespace giada {
+namespace v
+{
+gdSampleActionEditor::gdSampleActionEditor(SampleChannel* ch)
+: gdBaseActionEditor(ch)
+{
+       computeWidth();
+
+       /* Container with zoom buttons and the action type selector. Scheme of the 
+       resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
+
+       Fl_Group* upperArea = new Fl_Group(8, 8, w()-16, 20);
+
+       upperArea->begin();
+
+         actionType = new geChoice(8, 8, 80, 20);
+         gridTool   = new geGridTool(actionType->x()+actionType->w()+4, 8);
+               actionType->add("Key press");
+               actionType->add("Key release");
+               actionType->add("Kill chan");
+               actionType->value(0);
+
+               if (!canChangeActionType())
+                       actionType->deactivate();
+
+               geBox* b1  = new geBox(gridTool->x()+gridTool->w()+4, 8, 300, 20);    // padding actionType - zoomButtons
+               zoomInBtn  = new geButton(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+               zoomOutBtn = new geButton(w()-8-20,   8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
+
+       upperArea->end();
+       upperArea->resizable(b1);
+
+       zoomInBtn->callback(cb_zoomIn, (void*)this);
+       zoomOutBtn->callback(cb_zoomOut, (void*)this);
+
+       /* Main viewport: contains all widgets. */
+
+       viewport = new geScroll(8, 36, w()-16, h()-44);
+
+       ac = new geSampleActionEditor(viewport->x(), viewport->y(), ch);
+       viewport->add(ac);
+       viewport->add(new geResizerBar(ac->x(), ac->y()+ac->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       
+       vc = new geEnvelopeEditor(viewport->x(), ac->y()+ac->h()+RESIZER_BAR_H, G_ACTION_VOLUME, "volume", ch);
+       viewport->add(vc);
+       viewport->add(new geResizerBar(vc->x(), vc->y()+vc->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+
+       end();
+       prepareWindow();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gdSampleActionEditor::canChangeActionType()
+{
+       SampleChannel* sch = static_cast<SampleChannel*>(ch); 
+       return sch->mode != ChannelMode::SINGLE_PRESS && !sch->isAnyLoopMode();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdSampleActionEditor::rebuild()
+{
+       canChangeActionType() ? actionType->activate() : actionType->deactivate(); 
+       computeWidth();
+       ac->rebuild();
+       vc->rebuild();  
+}
+}} // giada::v::
diff --git a/src/gui/dialogs/actionEditor/sampleActionEditor.h b/src/gui/dialogs/actionEditor/sampleActionEditor.h
new file mode 100644 (file)
index 0000000..9832f21
--- /dev/null
@@ -0,0 +1,61 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_SAMPLE_ACTION_EDITOR_H
+#define GD_SAMPLE_ACTION_EDITOR_H
+
+
+#include "baseActionEditor.h"
+
+
+class SampleChannel;
+class geSampleActionEditor;
+class geEnvelopeEditor;
+
+
+namespace giada {
+namespace v
+{
+class gdSampleActionEditor : public gdBaseActionEditor
+{
+private:
+
+       geSampleActionEditor* ac;
+       geEnvelopeEditor*     vc;
+
+       bool canChangeActionType();
+       
+public:
+
+       gdSampleActionEditor(SampleChannel* ch);
+
+       void rebuild() override;
+};
+}} // giada::v::
+
+
+#endif
diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp
deleted file mode 100644 (file)
index 499f9a3..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <cmath>
-#include "../../utils/gui.h"
-#include "../../utils/string.h"
-#include "../../core/graphics.h"
-#include "../../core/conf.h"
-#include "../../core/const.h"
-#include "../../core/clock.h"
-#include "../../core/sampleChannel.h"
-#include "../elems/basics/scroll.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/resizerBar.h"
-#include "../elems/basics/choice.h"
-#include "../elems/basics/box.h"
-#include "../elems/actionEditor/actionEditor.h"
-#include "../elems/actionEditor/envelopeEditor.h"
-#include "../elems/actionEditor/muteEditor.h"
-#include "../elems/actionEditor/noteEditor.h"
-#include "../elems/actionEditor/gridTool.h"
-#include "gd_actionEditor.h"
-
-
-using std::string;
-using namespace giada;
-using namespace giada::m;
-
-
-gdActionEditor::gdActionEditor(Channel* chan)
-       :       gdWindow(640, 284),
-               chan   (chan),
-               zoom   (100),
-               coverX (0)
-{
-       if (conf::actionEditorW) {
-               resize(conf::actionEditorX, conf::actionEditorY, conf::actionEditorW, conf::actionEditorH);
-               zoom = conf::actionEditorZoom;
-       }
-
-       totalWidth = (int) std::ceil(clock::getFramesInSeq() / (float) zoom);
-
-       /* container with zoom buttons and the action type selector. Scheme of
-        * the resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
-
-       Fl_Group *upperArea = new Fl_Group(8, 8, w()-16, 20);
-
-       upperArea->begin();
-
-       if (chan->type == ChannelType::SAMPLE) {
-         actionType = new geChoice(8, 8, 80, 20);
-         gridTool   = new geGridTool(actionType->x()+actionType->w()+4, 8, this);
-               actionType->add("key press");
-               actionType->add("key release");
-               actionType->add("kill chan");
-               actionType->value(0);
-
-               SampleChannel *ch = static_cast<SampleChannel*>(chan);
-               if (ch->mode == ChannelMode::SINGLE_PRESS || ch->isAnyLoopMode())
-               actionType->deactivate();
-       }
-       else {
-               gridTool = new geGridTool(8, 8, this);
-       }
-
-               geBox *b1   = new geBox(gridTool->x()+gridTool->w()+4, 8, 300, 20);    // padding actionType - zoomButtons
-               zoomIn     = new geButton(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
-               zoomOut    = new geButton(w()-8-20,   8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
-       upperArea->end();
-       upperArea->resizable(b1);
-
-       zoomIn->callback(cb_zoomIn, (void*)this);
-       zoomOut->callback(cb_zoomOut, (void*)this);
-
-       /* main scroller: contains all widgets */
-
-       scroller = new geScroll(8, 36, w()-16, h()-44);
-
-       if (chan->type == ChannelType::SAMPLE) {
-
-               SampleChannel *ch = static_cast<SampleChannel*>(chan);
-
-               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, G_ACTION_VOLUME, G_RANGE_FLOAT, "volume");
-               scroller->add(ac);
-               //scroller->add(new geResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8));
-               scroller->add(mc);
-               //scroller->add(new geResizerBar(mc->x(), mc->y()+mc->h(), scroller->w(), 8));
-               scroller->add(vc);
-               //scroller->add(new geResizerBar(vc->x(), vc->y()+vc->h(), scroller->w(), 8));
-
-               /* fill volume envelope with actions from recorder */
-
-               vc->fill();
-
-               /* if channel is LOOP_ANY, deactivate it: a loop mode channel cannot
-                * hold keypress/keyrelease actions */
-
-               if (ch->isAnyLoopMode())
-                       ac->deactivate();
-       }
-       else {
-               pr = new geNoteEditor(scroller->x(), upperArea->y()+upperArea->h()+8, this);
-               scroller->add(pr);
-               /* TODO - avoid magic number 30 for minimum height */
-               scroller->add(new geResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 30, 8));
-       }
-
-       end();
-
-       /* compute values */
-
-       update();
-       gridTool->calc();
-
-       gu_setFavicon(this);
-
-       string buf = "Edit Actions in Channel " + gu_iToString(chan->index+1);
-       label(buf.c_str());
-
-       set_non_modal();
-       size_range(640, 284);
-       resizable(scroller);
-
-       show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdActionEditor::~gdActionEditor()
-{
-       conf::actionEditorX = x();
-       conf::actionEditorY = y();
-       conf::actionEditorW = w();
-       conf::actionEditorH = h();
-       conf::actionEditorZoom = zoom;
-
-       /** CHECKME - missing clear() ? */
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdActionEditor::cb_zoomIn(Fl_Widget *w, void *p)  { ((gdActionEditor*)p)->__cb_zoomIn(); }
-void gdActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomOut(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdActionEditor::__cb_zoomIn()
-{
-       /* zoom 50: empirical value, to avoid a totalWidth > 16 bit signed
-        * (32767 max), unsupported by FLTK 1.3.x */
-
-       if (zoom <= 50)
-               return;
-
-       zoom /= 2;
-
-       update();
-
-       if (chan->type == ChannelType::SAMPLE) {
-               ac->size(totalWidth, ac->h());
-               mc->size(totalWidth, mc->h());
-               vc->size(totalWidth, vc->h());
-               ac->updateActions();
-               mc->updateActions();
-               vc->updateActions();
-       }
-       else {
-               pr->size(totalWidth, pr->h());
-               pr->updateActions();
-       }
-
-       /* scroll to pointer */
-
-       int shift = Fl::event_x() + scroller->xposition();
-       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
-
-       /* update all underlying widgets */
-
-       gridTool->calc();
-       scroller->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdActionEditor::__cb_zoomOut()
-{
-       zoom *= 2;
-
-       update();
-
-       if (chan->type == ChannelType::SAMPLE) {
-               ac->size(totalWidth, ac->h());
-               mc->size(totalWidth, mc->h());
-               vc->size(totalWidth, vc->h());
-               ac->updateActions();
-               mc->updateActions();
-               vc->updateActions();
-       }
-       else {
-               pr->size(totalWidth, pr->h());
-               pr->updateActions();
-       }
-
-       /* scroll to pointer */
-
-       int shift = (Fl::event_x() + scroller->xposition()) / -2;
-       if (scroller->xposition() + shift < 0)
-                       shift = 0;
-       scroller->scroll_to(scroller->xposition() + shift, scroller->yposition());
-
-       /* update all underlying widgets */
-
-       gridTool->calc();
-       scroller->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdActionEditor::update()
-{
-       totalWidth = (int) ceilf(clock::getFramesInSeq() / (float) zoom);
-       if (totalWidth < scroller->w()) {
-               totalWidth = scroller->w();
-               zoom = (int) ceilf(clock::getFramesInSeq() / (float) totalWidth);
-               scroller->scroll_to(0, scroller->yposition());
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gdActionEditor::handle(int e)
-{
-       int ret = Fl_Group::handle(e);
-       switch (e) {
-               case FL_MOUSEWHEEL: {
-                       Fl::event_dy() == -1 ? __cb_zoomIn() : __cb_zoomOut();
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gdActionEditor::getActionType()
-{
-       if (actionType->value() == 0)
-               return G_ACTION_KEYPRESS;
-       else
-       if (actionType->value() == 1)
-               return G_ACTION_KEYREL;
-       else
-       if (actionType->value() == 2)
-               return G_ACTION_KILL;
-       else
-               return -1;
-}
diff --git a/src/gui/dialogs/gd_actionEditor.h b/src/gui/dialogs/gd_actionEditor.h
deleted file mode 100644 (file)
index f82a6f7..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GD_ACTIONEDITOR_H
-#define GD_ACTIONEDITOR_H
-
-
-#include <vector>
-#include <FL/Fl.H>
-#include <FL/Fl_Double_Window.H>
-#include <FL/Fl_Scroll.H>
-#include "window.h"
-
-
-class Channel;
-class geChoice;
-class geGridTool;
-class geButton;
-class geButton;
-class geScroll;
-class geActionEditor;
-class geMuteEditor;
-class geEnvelopeEditor;
-class geNoteEditor;
-
-
-/* gActionEditor
-Main window which contains the tools for dealing with actions. 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 gdWindow
-{
-private:
-
-       /* update
-  Computes total width, in pixel. */
-
-       void update();
-
-public:
-
-       gdActionEditor(Channel *chan);
-       ~gdActionEditor();
-
-       int handle(int e);
-
-       int getActionType();
-
-       static void cb_zoomIn(Fl_Widget *w, void *p);
-       static void cb_zoomOut(Fl_Widget *w, void *p);
-       inline void __cb_zoomIn();
-       inline void __cb_zoomOut();
-
-       geChoice   *actionType;
-       geGridTool *gridTool;
-       geButton   *zoomIn;
-       geButton   *zoomOut;
-       geScroll   *scroller;       // widget container
-
-       geActionEditor   *ac;
-       geMuteEditor     *mc;
-       geEnvelopeEditor *vc;
-       geNoteEditor     *pr;
-
-       Channel *chan;
-
-       int zoom;
-       int totalWidth;  // total width of the widget, in pixel (zoom affected)
-       int coverX;              // x1 of the unused area (x2 = totalWidth)
-};
-
-
-#endif
index 35c9ec6ccfac554c6527fae4a36a6fdd73c741a6..0e64c3acaf64d8830a365d0fadc60df4bfcc1bd8 100644 (file)
@@ -45,11 +45,15 @@ using namespace giada::m;
 
 
 gdPluginWindowGUI::gdPluginWindowGUI(Plugin* plugin)
- : gdWindow(450, 300), m_plugin(plugin)
+#ifdef G_OS_MAC
+ : gdWindow(Fl::w(), Fl::h()), m_plugin(plugin)
+#else
+ : gdWindow(320, 200), m_plugin(plugin)
+#endif
 {
   show();
 
-#ifdef G_OS_LINUX
+#if defined(G_OS_LINUX) || defined(G_OS_MAC)
 
   /*  Fl_Window::show() is not guaranteed to show and draw the window on all 
   platforms immediately. Instead this is done in the background; particularly on 
@@ -58,19 +62,11 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin* plugin)
   want to have the window instantiated and displayed synchronously. Currently 
   (as of FLTK 1.3.4) this method has an effect on X11 and Mac OS. 
 
-  http://www.fltk.org/doc-1.3/classFl__Window.html#aafbec14ca8ff8abdaff77a35ebb23dd8
-  
-  NOTE - we should try to macOS as well. */
+  http://www.fltk.org/doc-1.3/classFl__Window.html#aafbec14ca8ff8abdaff77a35ebb23dd8 */
 
   wait_for_expose();
   Fl::flush();
 
-#endif
-
-#ifndef G_OS_MAC
-
-  Fl::check();
-
 #endif
 
   gu_log("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
@@ -79,20 +75,20 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin* plugin)
 #ifdef G_OS_MAC
 
   void* cocoaWindow = (void*) fl_xid(this);
-  cocoa_setWindowSize(cocoaWindow, m_plugin->getEditorW(), m_plugin->getEditorH());
   m_plugin->showEditor(cocoa_getViewFromWindow(cocoaWindow));
 
 #else
 
   m_plugin->showEditor((void*) fl_xid(this));
 
-#endif
-
   int pluginW = m_plugin->getEditorW();
   int pluginH = m_plugin->getEditorH();
 
   resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH);
 
+
+#endif
+
   Fl::add_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
 
   copy_label(m_plugin->getName().c_str());
diff --git a/src/gui/elems/actionEditor/action.cpp b/src/gui/elems/actionEditor/action.cpp
deleted file mode 100644 (file)
index 9a85940..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "../../../core/const.h"
-#include "../../../core/mixer.h"
-#include "../../../core/sampleChannel.h"
-#include "../../../utils/log.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "actionEditor.h"
-#include "action.h"
-
-
-using namespace giada;
-using namespace giada::m;
-
-
-/** TODO - index is useless?
- *  TODO - pass a record::action pointer and let geAction compute values */
-
-geAction::geAction(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 == ChannelMode::SINGLE_PRESS && type == G_ACTION_KEYPRESS) {
-               recorder::action *a2 = nullptr;
-               recorder::getNextAction(ch->index, G_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 geAction::draw()
-{
-       int color;
-       if (selected)  /// && geActionEditor !disabled
-               color = G_COLOR_LIGHT_2;
-       else
-               color = G_COLOR_LIGHT_1;
-
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               fl_rectf(x(), y(), w(), h(), (Fl_Color) color);
-       }
-       else {
-               if (type == G_ACTION_KILL)
-                       fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-               else {
-                       fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color);
-                       if (type == G_ACTION_KEYPRESS)
-                               fl_rectf(x()+3, y()+h()-11, 2, 8, G_COLOR_GREY_4);
-                       else
-                       if  (type == G_ACTION_KEYREL)
-                               fl_rectf(x()+3, y()+3, 2, 8, G_COLOR_GREY_4);
-               }
-       }
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geAction::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 == ChannelMode::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 geAction::addAction()
-{
-       /* anatomy of an action
-        * ____[#######]_____ (a) is the left margin, G_ACTION_KEYPRESS. (b) is
-        *     a       b      the right margin, the G_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 == ChannelMode::SINGLE_PRESS) {
-               recorder::rec(parent->chan->index, G_ACTION_KEYPRESS, frame_a);
-               recorder::rec(parent->chan->index, G_ACTION_KEYREL, frame_a+4096);
-               //gu_log("action added, [%d, %d]\n", frame_a, frame_a+4096);
-       }
-       else {
-               recorder::rec(parent->chan->index, parent->getActionType(), frame_a);
-               //gu_log("action added, [%d]\n", frame_a);
-       }
-
-  parent->chan->hasActions = true;
-
-       recorder::sortActions();
-
-       index++; // important!
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geAction::delAction()
-{
-       /* if SINGLE_PRESS you must delete both the keypress and the keyrelease
-        * actions. */
-
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               recorder::deleteAction(parent->chan->index, frame_a, G_ACTION_KEYPRESS,
-      false, &mixer::mutex);
-               recorder::deleteAction(parent->chan->index, frame_b, G_ACTION_KEYREL,
-      false, &mixer::mutex);
-       }
-       else
-               recorder::deleteAction(parent->chan->index, frame_a, type, false,
-      &mixer::mutex);
-
-  parent->chan->hasActions = recorder::hasActions(parent->chan->index);
-
-
-       /* 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 geAction::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 == ChannelMode::SINGLE_PRESS) {
-               frame_b = xToFrame_b();
-               recorder::rec(parent->chan->index, G_ACTION_KEYREL, frame_b);
-       }
-
-  parent->chan->hasActions = true;
-
-       recorder::sortActions();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geAction::absx()
-{
-       return x() - parent->ac->x();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geAction::xToFrame_a()
-{
-       return (absx()) * parent->zoom;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geAction::xToFrame_b()
-{
-       return (absx() + w()) * parent->zoom;
-}
diff --git a/src/gui/elems/actionEditor/action.h b/src/gui/elems/actionEditor/action.h
deleted file mode 100644 (file)
index f681d56..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_ACTION_H
-#define GE_ACTION_H
-
-
-#include <FL/Fl_Box.H>
-
-
-class gdActionEditor;
-class SampleChannel;
-
-
-class geAction : public Fl_Box
-{
-private:
-
-       bool            selected;
-       unsigned        index;
-  gdActionEditor *parent;   // pointer to parent (geActionEditor)
-       SampleChannel  *ch;
-  char            type;     // type of action
-
-public:
-
-       geAction(int x, int y, int h, int frame_a, unsigned index,
-               gdActionEditor *parent, 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;
-};
-
-
-#endif
diff --git a/src/gui/elems/actionEditor/actionEditor.cpp b/src/gui/elems/actionEditor/actionEditor.cpp
deleted file mode 100644 (file)
index 72a23fc..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "../../../core/clock.h"
-#include "../../../core/sampleChannel.h"
-#include "../../dialogs/gd_mainWindow.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "../mainWindow/keyboard/keyboard.h"
-#include "action.h"
-#include "gridTool.h"
-#include "actionEditor.h"
-
-
-extern gdMainWindow *G_MainWin;
-
-
-using namespace giada;
-using namespace giada::m;
-
-
-geActionEditor::geActionEditor(int x, int y, gdActionEditor *pParent, SampleChannel *ch)
-  : geBaseActionEditor(x, y, 200, 40, pParent),
-    ch                (ch),
-    selected          (nullptr)
-{
-       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 G_ACTION_KILL 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 G_ACTION_KEYREL in a SINGLE_PRESS channel. It's up to geAction to
-        find the other piece (namely frame_b)
-      - not of types G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL */
-
-      if ((action->chan != pParent->chan->index)                          ||
-          (recorder::frames.at(i) > clock::getFramesInLoop())             ||
-          (action->type == G_ACTION_KILL && ch->mode == ChannelMode::SINGLE_PRESS)     ||
-          (action->type == G_ACTION_KEYREL && ch->mode == ChannelMode::SINGLE_PRESS)   ||
-          (action->type & ~(G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL))
-      )
-        continue;
-
-                       int ax = x + (action->frame / pParent->zoom);
-                       geAction *a = new geAction(
-                                       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
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-geAction *geActionEditor::getSelectedAction()
-{
-       for (int i=0; i<children(); i++) {
-               int action_x  = ((geAction*)child(i))->x();
-               int action_w  = ((geAction*)child(i))->w();
-               if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w)
-                       return (geAction*)child(i);
-       }
-       return nullptr;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-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 */
-
-       geAction *a;
-       for (int i=0; i<children(); i++) {
-
-               a = (geAction*)child(i);
-               int newX = x() + (a->frame_a / pParent->zoom);
-
-               if (ch->mode == ChannelMode::SINGLE_PRESS) {
-                       int newW = ((a->frame_b - a->frame_a) / pParent->zoom);
-                       if (newW < geAction::MIN_WIDTH)
-                               newW = geAction::MIN_WIDTH;
-                       a->resize(newX, a->y(), newW, a->h());
-               }
-               else
-                       a->resize(newX, a->y(), geAction::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(G_COLOR_GREY_4);
-       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 == nullptr) {  // 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()+geAction::MIN_WIDTH)
-                                               aw = geAction::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()-geAction::MIN_WIDTH) {
-                                               ax = selected->x()+selected->w()-geAction::MIN_WIDTH;
-                                               aw = geAction::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 == nullptr) {
-
-                                       /* 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;
-                                               }
-                                       }
-
-                                       geAction *a = new geAction(
-                                                       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);
-                                       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()) {
-                               geAction *a = getSelectedAction();
-                               if (a != nullptr) {
-                                       a->delAction();
-                                       remove(a);
-                                       delete a;
-                                       G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel);
-                                       redraw();
-                                       ret = 1;
-                               }
-                       }
-                       break;
-               }
-               case FL_RELEASE: {
-
-                       if (selected == nullptr) {
-                               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 == ChannelMode::SINGLE_PRESS &&
-                                       actionOriginalX+actionOriginalW != selected->x()+selected->w())
-                               noChanges = false;
-
-                       if (noChanges) {
-                               ret = 1;
-                               selected = nullptr;
-                               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 ((geAction*)child(i) == selected)
-                                       continue;
-
-                               int action_x  = ((geAction*)child(i))->x();
-                               int action_w  = ((geAction*)child(i))->w();
-                               if (ch->mode == ChannelMode::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 nullptr, 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 = nullptr;
-                       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 (((geAction*) child(i))->frame_a == frame)
-                       collision = true;
-
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               for (int i=0; i<children() && !collision; i++) {
-                       geAction *c = ((geAction*) child(i));
-                       if (frame <= c->frame_b && frame >= c->frame_a)
-                               collision = true;
-               }
-       }
-
-       return collision;
-}
diff --git a/src/gui/elems/actionEditor/actionEditor.h b/src/gui/elems/actionEditor/actionEditor.h
deleted file mode 100644 (file)
index 5870cca..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_ACTION_EDITOR_H
-#define GE_ACTION_EDITOR_H
-
-
-#include "baseActionEditor.h"
-
-
-class geAction;
-class SampleChannel;
-
-
-class geActionEditor : public geBaseActionEditor
-{
-
-private:
-
-       SampleChannel *ch;
-
-       /* getSelectedAction
-        * get the action under the mouse. nullptr if nothing found. */
-
-       geAction *getSelectedAction();
-
-       /* selected
-        * pointer to the selected action. Useful when dragging around. */
-
-       geAction *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, SampleChannel *ch);
-       void draw();
-       int  handle(int e);
-       void updateActions();
-};
-
-
-#endif
diff --git a/src/gui/elems/actionEditor/baseAction.cpp b/src/gui/elems/actionEditor/baseAction.cpp
new file mode 100644 (file)
index 0000000..ba0d5f4
--- /dev/null
@@ -0,0 +1,133 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include "baseAction.h"
+
+
+namespace giada {
+namespace v
+{
+geBaseAction::geBaseAction(Pixel X, Pixel Y, Pixel W, Pixel H, bool resizable,
+       giada::m::recorder::action a1, giada::m::recorder::action a2)
+: Fl_Box     (X, Y, W, H),
+  m_resizable(resizable),
+  onRightEdge(false),
+  onLeftEdge (false),
+  hovered    (false),
+  altered    (false),
+  pick       (0),
+  a1         (a1),
+  a2         (a2)
+{
+       if (w() < MIN_WIDTH)
+               size(MIN_WIDTH, h());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geBaseAction::handle(int e)
+{
+       switch (e) {
+               case FL_ENTER: {
+                       hovered = true;
+                       redraw();
+                       return 1;
+               }
+               case FL_LEAVE: {
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       hovered = false;
+                       redraw();
+                       return 1;
+               }
+               case FL_MOVE: {
+                       if (m_resizable) {
+                               onLeftEdge  = false;
+                               onRightEdge = false;
+                               if (Fl::event_x() >= x() && Fl::event_x() < x() + HANDLE_WIDTH) {
+                                       onLeftEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                               if (Fl::event_x() >= x() + w() - HANDLE_WIDTH && 
+                                         Fl::event_x() <= x() + w()) {
+                                       onRightEdge = true;
+                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                               }
+                               else
+                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+                       }
+                       return 1;
+               }
+               default:
+                       return Fl_Widget::handle(e);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geBaseAction::setLeftEdge(Pixel p)
+{
+       resize(p, y(), x() - p + w(), h());
+       if (w() < MIN_WIDTH)
+               size(MIN_WIDTH, h());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geBaseAction::setRightEdge(Pixel p)
+{
+       size(p, h());
+       if (w() < MIN_WIDTH)
+               size(MIN_WIDTH, h());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geBaseAction::setPosition(Pixel p)
+{
+       position(p, y());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool geBaseAction::isOnEdges() const
+{
+       return onLeftEdge || onRightEdge;
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/elems/actionEditor/baseAction.h b/src/gui/elems/actionEditor/baseAction.h
new file mode 100644 (file)
index 0000000..d8bf4fd
--- /dev/null
@@ -0,0 +1,77 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_BASE_ACTION_H
+#define GE_BASE_ACTION_H
+
+
+#include <FL/Fl_Box.H>
+#include "../../../core/recorder.h"
+#include "../../../core/types.h"
+
+
+namespace giada {
+namespace v
+{
+class geBaseAction : public Fl_Box
+{
+private:
+       
+       bool m_resizable;
+
+public:
+
+       static const Pixel MIN_WIDTH    = 12;
+       static const Pixel HANDLE_WIDTH = 6;
+
+       geBaseAction(Pixel x, Pixel y, Pixel w, Pixel h, bool resizable, 
+               m::recorder::action a1, m::recorder::action a2);
+
+       int handle(int e) override;
+
+       bool isOnEdges() const;
+
+       /* setLeftEdge/setRightEdge
+       Set new left/right edges position, relative range. */
+
+       void setLeftEdge(Pixel p);
+       void setRightEdge(Pixel p);
+
+       void setPosition(Pixel p);
+
+       bool onRightEdge;
+       bool onLeftEdge;
+       bool hovered;
+       bool altered;
+       Pixel pick;
+
+       m::recorder::action a1;
+       m::recorder::action a2;
+};
+}} // giada::v::
+
+#endif
index 0f11b318ffdea2fa76572375df63a2b48917906a..c59b12d03e6a6eae0847817066de68663d21a2d6 100644 (file)
@@ -2,9 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * geBaseActionEditor
- * Parent class of any widget inside the action editor.
- *
  * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  * -------------------------------------------------------------------------- */
 
 
+#include <FL/Fl.H>
 #include <FL/fl_draw.H>
-#include "../../../core/mixer.h"
 #include "../../../core/const.h"
-#include "../../dialogs/gd_actionEditor.h"
+#include "../../../core/clock.h"
+#include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "gridTool.h"
+#include "baseAction.h"
 #include "baseActionEditor.h"
 
 
-geBaseActionEditor::geBaseActionEditor(int x, int y, int w, int h,
-       gdActionEditor *pParent)
-       :       Fl_Group(x, y, w, h), pParent(pParent) {}
+namespace giada {
+namespace v
+{
+geBaseActionEditor::geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, Channel* ch)
+:      Fl_Group(x, y, w, h),
+  m_ch    (ch),
+  m_base  (static_cast<gdBaseActionEditor*>(window())),
+  m_action(nullptr)
+{
+}
 
 
 /* -------------------------------------------------------------------------- */
 
 
-geBaseActionEditor::~geBaseActionEditor() {}
+geBaseAction* geBaseActionEditor::getActionAtCursor() const
+{
+       for (int i=0; i<children(); i++) {
+               geBaseAction* a = static_cast<geBaseAction*>(child(i));
+               if (a->hovered)
+                       return a;
+       }
+       return nullptr;
+}
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geBaseActionEditor::baseDraw(bool clear) {
-
-       /* clear the screen */
+void geBaseActionEditor::baseDraw(bool clear) const
+{
+       /* Clear the screen. */
 
        if (clear)
                fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_1);
 
-       /* draw the container */
+       /* Draw the outer container. */
 
        fl_color(G_COLOR_GREY_4);
        fl_rect(x(), y(), w(), h());
 
-       /* grid drawing, if > 1 */
+       /* Draw grid, beats and bars. A grid set to 1 has a cell size == beat, so
+       painting it is useless. */
 
-       if (pParent->gridTool->getValue() > 1) {
+       if (m_base->gridTool->getValue() > 1) {
+               fl_color(G_COLOR_GREY_3);
+               drawVerticals(m_base->gridTool->getCellSize());
+       }
 
-               fl_color(fl_rgb_color(54, 54, 54));
-               fl_line_style(FL_DASH, 0, nullptr);
+       fl_color(G_COLOR_GREY_4);
+       drawVerticals(m::clock::getFramesInBeat());
 
-               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);
-       }
+       fl_color(G_COLOR_LIGHT_1);
+       drawVerticals(m::clock::getFramesInBar());
 
-       /* bars and beats drawing */
+       /* Cover unused area. Avoid drawing cover if width == 0 (i.e. beats are 32). */
 
-       fl_color(G_COLOR_GREY_4);
-       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);
+       Pixel coverWidth = m_base->fullWidth - m_base->loopWidth;
+       if (coverWidth != 0)
+               fl_rectf(m_base->loopWidth+x(), y()+1, coverWidth, h()-2, G_COLOR_GREY_4);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geBaseActionEditor::drawVerticals(int steps) const
+{
+       /* Start drawing from steps, not from 0. The zero-th element is always 
+       graphically useless. */
+       for (Frame i=steps; i<m::clock::getFramesInLoop(); i+=steps) {
+               Pixel p = m_base->frameToPixel(i) + x();
+               fl_line(p, y()+1, p, y()+h()-2);
+       }       
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+int geBaseActionEditor::handle(int e)
+{
+       switch (e) {
+               case FL_PUSH:
+                       return push();
+               case FL_DRAG:
+                       return drag();
+               case FL_RELEASE:
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); // Make sure cursor returns normal
+                       return release();
+               default:
+                       return Fl_Group::handle(e);
        }
+}
 
-       fl_color(G_COLOR_LIGHT_1);
-       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);
+
+/* -------------------------------------------------------------------------- */
+
+
+int geBaseActionEditor::push()
+{
+       m_action = getActionAtCursor();
+
+       if (Fl::event_button1()) {    // Left button
+               if (m_action == nullptr) {  // No action under cursor: add a new one
+                       if (Fl::event_x() < m_base->loopWidth) // Avoid click on grey area
+                               onAddAction();
+               }
+               else                        // Prepare for dragging
+                       m_action->pick = Fl::event_x() - m_action->x();
        }
+       else
+       if (Fl::event_button3()) {    // Right button
+               if (m_action != nullptr) {
+                       onDeleteAction();
+                       m_action = nullptr;
+               }
+       }
+       return 1;       
+}
 
-       /* 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, G_COLOR_GREY_4);
+/* -------------------------------------------------------------------------- */
+
+
+int geBaseActionEditor::drag()
+{
+       if (m_action == nullptr)
+               return 0;
+       if (m_action->isOnEdges())
+               onResizeAction();
+       else
+               onMoveAction();
+       m_action->altered = true;
+       redraw();
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geBaseActionEditor::release()
+{
+       int ret = 0;
+       if (m_action != nullptr && m_action->altered) {
+               onRefreshAction();
+               ret = 1;
+       }
+       m_action = nullptr;
+       return ret;
 }
+}} // giada::v::
\ No newline at end of file
index d0862de336bc5421eec596b53bff19179df51566..0f3d2edf2717d22dac2de2a7bed982d9bdb1798b 100644 (file)
@@ -2,9 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * ge_actionWidget
- *
- * parent class of any tool inside the action editor.
  *
  * -----------------------------------------------------------------------------
  *
 #include <FL/Fl_Group.H>
 
 
-class gdActionEditor;
+class Channel;
+
 
+namespace giada {
+namespace v
+{
+class gdBaseActionEditor;
+class geBaseAction;
 
 class geBaseActionEditor : public Fl_Group
 {
+private:
+       
+       /* drawVerticals
+       Draws generic vertical lines (beats, bars, grid lines...). */
+       
+       void drawVerticals(int steps) const;
+       
+       int push();
+       int drag();
+       int release();
+
 protected:
 
-       gdActionEditor *pParent;
+       Channel* m_ch;
+
+       gdBaseActionEditor* m_base;
+
+       /* m_action
+       Selected action. Used while dragging. */
+
+       geBaseAction* m_action;
 
-  void baseDraw(bool clear=true);
+       /* baseDraw
+       Draws basic things like borders and grids. Optional background clear. */
+
+  void baseDraw(bool clear=true) const;
+
+       virtual void onAddAction()     = 0;
+       virtual void onDeleteAction()  = 0;
+       virtual void onMoveAction()    = 0;
+       virtual void onResizeAction()  = 0;
+       virtual void onRefreshAction() = 0;
 
 public:
 
-       virtual void updateActions() = 0;
+       geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, Channel* ch);
+
+  /* updateActions
+  Rebuild the actions widgets from scratch. */
+  
+       virtual void rebuild() = 0;
 
-       geBaseActionEditor(int x, int y, int w, int h, gdActionEditor *pParent);
-       ~geBaseActionEditor();
+       /* handle
+       Override base FL_Group events. */
+       
+       int handle(int e) override;
+
+       /* getActionAtCursor
+       Returns the action under the mouse. nullptr if nothing found. Why not using
+       Fl::belowmouse? It would require a boring dynamic_cast. */
+
+       geBaseAction* getActionAtCursor() const;        
 };
+}} // giada::v::
+
 
 #endif
diff --git a/src/gui/elems/actionEditor/basePianoItem.cpp b/src/gui/elems/actionEditor/basePianoItem.cpp
deleted file mode 100644 (file)
index 439c91a..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "pianoRoll.h"
-#include "basePianoItem.h"
-
-
-geBasePianoItem::geBasePianoItem(int x, int y, int w, gdActionEditor *pParent)
-  : Fl_Box  (x, y, w, gePianoRoll::CELL_H),
-    pParent (pParent),
-    selected(false)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geBasePianoItem::handle(int e)
-{
-  int ret = 0;
-       switch (e) {
-               case FL_ENTER:
-      selected = true;
-      redraw();
-      ret = 1;
-      break;
-    case FL_LEAVE:
-      selected = false;
-      redraw();
-      ret = 1;
-      break;
-  }
-  return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geBasePianoItem::getY(int note)
-{
-  return (gePianoRoll::MAX_KEYS * gePianoRoll::CELL_H) - (note * gePianoRoll::CELL_H);
-}
diff --git a/src/gui/elems/actionEditor/basePianoItem.h b/src/gui/elems/actionEditor/basePianoItem.h
deleted file mode 100644 (file)
index 41d7de4..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_BASE_PIANO_ITEM_H
-#define GE_BASE_PIANO_ITEM_H
-
-
-#include <FL/Fl_Box.H>
-#include "../../../core/recorder.h"
-
-
-class gdActionEditor;
-
-
-class geBasePianoItem : public Fl_Box
-{
-protected:
-
-  geBasePianoItem(int x, int y, int w, gdActionEditor *pParent);
-
-  /* getY
-        * from a note, return the y position on piano roll */
-
-       int getY(int note);
-
-  gdActionEditor *pParent;
-
-  bool selected;
-
-public:
-
-  virtual void reposition(int pianoRollX) = 0;
-
-  int handle(int e) override;
-};
-
-
-#endif
index 4e032a82b04d04c19100f5cd84371d619439c0b4..b1bba63cef8a6c8c16da8319dcdab565e673dcdb 100644 (file)
@@ -2,11 +2,6 @@
  *
  * Giada - Your Hardcore Loopmachine
  *
- * envelopeEditor
- *
- * Parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
  * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  * -------------------------------------------------------------------------- */
 
 
+#include <FL/Fl.H>
 #include <FL/fl_draw.H>
-#include "../../../core/channel.h"
-#include "../../../core/recorder.h"
-#include "../../../core/mixer.h"
-#include "../../../core/clock.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "../../dialogs/gd_mainWindow.h"
-#include "../mainWindow/keyboard/keyboard.h"
-#include "gridTool.h"
+#include "../../../utils/log.h"
+#include "../../../utils/math.h"
+#include "../../../core/const.h"
+#include "../../../core/conf.h"
+#include "../../../core/sampleChannel.h"
+#include "../../../glue/recorder.h"
+#include "../../dialogs/actionEditor/baseActionEditor.h"
+#include "envelopePoint.h"
 #include "envelopeEditor.h"
 
 
-extern gdMainWindow *G_MainWin;
-
+using std::vector;
 
-using namespace giada::m;
 
-
-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)
+namespace giada {
+namespace v
+{
+geEnvelopeEditor::geEnvelopeEditor(Pixel x, Pixel y, int actionType, const char* l, 
+       SampleChannel* ch)
+:      geBaseActionEditor(x, y, 200, m::conf::envelopeEditorH, ch),    
+  m_actionType      (actionType)
 {
-       size(pParent->totalWidth, h());
+       copy_label(l);
+       rebuild();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-geEnvelopeEditor::~geEnvelopeEditor() {
-       clearPoints();
+geEnvelopeEditor::~geEnvelopeEditor()
+{
+       m::conf::envelopeEditorH = h();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-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::draw() 
+{
+       baseDraw();
 
-/* ------------------------------------------------------------------ */
+       /* Print label. */
 
+       fl_color(G_COLOR_GREY_4);
+       fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
+       fl_draw(label(), x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT));
+
+       if (children() == 0)
+               return;
+
+       Pixel side = geEnvelopePoint::SIDE / 2;
+
+       Pixel x1 = child(0)->x() + side;
+       Pixel y1 = child(0)->y() + side;
+       Pixel x2 = 0;
+       Pixel y2 = 0;
+
+       /* For each point: 
+               - paint the connecting line with the next one;
+               - reposition it on the y axis, only if there's no point selected (dragged
+           around). */
+
+       for (int i=0; i<children(); i++) {
+               geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
+               if (m_action == nullptr)
+                       p->position(p->x(), valueToY(p->a1.fValue));
+               if (i > 0) {
+                       x2 = p->x() + side;
+                       y2 = p->y() + side;
+                       fl_line(x1, y1, x2, y2);
+                       x1 = x2;
+                       y1 = y2;
+               }
+       }
 
-void geEnvelopeEditor::updateActions() {
-       for (unsigned i=0; i<points.size(); i++)
-               points.at(i).x = points.at(i).frame / pParent->zoom;
+       draw_children();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void geEnvelopeEditor::draw() {
+void geEnvelopeEditor::rebuild()
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
 
-       baseDraw();
+       /* Remove all existing actions and set a new width, according to the current
+       zoom level. */
 
-       /* print label */
+       clear();
+       size(m_base->fullWidth, h());
 
-       fl_color(G_COLOR_GREY_4);
-       fl_font(FL_HELVETICA, 12);
-       fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT));
+       vector<mr::action> actions = cr::getEnvelopeActions(m_ch, m_actionType);
 
-       int pxOld = x()-3;
-       int pyOld = y()+1;
-       int pxNew = 0;
-       int pyNew = 0;
+       for (mr::action a : actions) {
+               gu_log("[geEnvelopeEditor::rebuild] Action %d\n", a.frame);
+               add(new geEnvelopePoint(frameToX(a.frame), valueToY(a.fValue), a));             
+       }
 
-       fl_color(G_COLOR_LIGHT_1);
+       resizable(nullptr);
 
-       for (unsigned i=0; i<points.size(); i++) {
+       redraw();
+}
 
-               pxNew = points.at(i).x+x()-3;
-               pyNew = points.at(i).y+y();
 
-               if (selectedPoint == (int) i) {
-                       fl_color(G_COLOR_LIGHT_1);
-                       fl_rectf(pxNew, pyNew, 7, 7);
-                       fl_color(G_COLOR_LIGHT_1);
-               }
-               else
-                       fl_rectf(pxNew, pyNew, 7, 7);
+/* -------------------------------------------------------------------------- */
 
-               if (i > 0)
-                       fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3);
 
-               pxOld = pxNew;
-               pyOld = pyNew;
-       }
+bool geEnvelopeEditor::isFirstPoint() const
+{
+       return find(m_action) == 0;
 }
 
 
-/* ------------------------------------------------------------------ */
+bool geEnvelopeEditor::isLastPoint() const
+{
+       return find(m_action) == children() - 1;
+}
 
 
-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
+Pixel geEnvelopeEditor::frameToX(Frame frame) const
+{
+       return x() + m_base->frameToPixel(frame) - (geEnvelopePoint::SIDE / 2);
+}
 
-       switch (e) {
 
-               case FL_ENTER: {
-                       ret = 1;
-                       break;
-               }
+Pixel geEnvelopeEditor::valueToY(float value) const
+{
+       return u::math::map<float, Pixel>(value, 0.0, 1.0, y() + (h() - geEnvelopePoint::SIDE), y());
+}
 
-               case FL_MOVE: {
-                       selectedPoint = getSelectedPoint();
-                       redraw();
-                       ret = 1;
-                       break;
-               }
 
-               case FL_LEAVE: {
-                       draggedPoint  = -1;
-                       selectedPoint = -1;
-                       redraw();
-                       ret = 1;
-                       break;
-               }
+float geEnvelopeEditor::yToValue(Pixel pixel) const
+{
+       return u::math::map<Pixel, float>(pixel, h() - geEnvelopePoint::SIDE, 0, 0.0, 1.0);     
+}
 
-               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 == G_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(clock::getFramesInLoop(), 0, 1.0f, pParent->coverX, 1);
-                                                       recorder::rec(pParent->chan->index, type, clock::getFramesInLoop(), 0, 1.0f);
-              pParent->chan->hasActions = true;
-                                               }
-
-                                               /* 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);
-            pParent->chan->hasActions = true;
-                                               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) {
-                                               recorder::clearAction(pParent->chan->index, type);
-            pParent->chan->hasActions = recorder::hasActions(pParent->chan->index);
-                                               points.clear();
-                                       }
-                                       else {
-                                               recorder::deleteAction(pParent->chan->index,
-              points.at(selectedPoint).frame, type, false, &mixer::mutex);
-            pParent->chan->hasActions = recorder::hasActions(pParent->chan->index);
-            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 > clock::getFramesInLoop())
-                                               newFrame = clock::getFramesInLoop();
-
-                                       /* 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, &mixer::mutex);
-          pParent->chan->hasActions = recorder::hasActions(pParent->chan->index);
-
-                                       if (range == G_RANGE_FLOAT) {
-                                               float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8);
-                                               recorder::rec(pParent->chan->index, type, newFrame, 0, value);
-            pParent->chan->hasActions = true;
-                                       }
-                                       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;
+void geEnvelopeEditor::onAddAction()     
+{
+       Frame f = m_base->pixelToFrame(Fl::event_x() - x());
+       float v = yToValue(Fl::event_y() - y());
+       c::recorder::recordEnvelopeAction(m_ch, m_actionType, f, v);
+       rebuild();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-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::onDeleteAction()  
+{
+       c::recorder::deleteEnvelopeAction(m_ch, m_action->a1, /*moved=*/false);
+       rebuild();
 }
 
 
-/* ------------------------------------------------------------------ */
-
-
-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));
-}
+/* -------------------------------------------------------------------------- */
 
 
-/* ------------------------------------------------------------------ */
+void geEnvelopeEditor::onMoveAction()    
+{
+       Pixel side = geEnvelopePoint::SIDE / 2;
+       Pixel ex   = Fl::event_x() - side;
+       Pixel ey   = Fl::event_y() - side;
 
+       Pixel x1 = x() - side;
+       Pixel x2 = m_base->loopWidth + x() - side;
+       Pixel y1 = y();
+       Pixel y2 = y() + h() - geEnvelopePoint::SIDE;
 
-int geEnvelopeEditor::getSelectedPoint() {
+       /* x-axis constraints. */
+       if      (isFirstPoint() || ex < x1) ex = x1; 
+       else if (isLastPoint()  || ex > x2) ex = x2;
 
-       /* point is a 7x7 dot */
+       /* y-axis constraints. */
+       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
 
-       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;
+       m_action->position(ex, ey);
+       redraw();
 }
 
 
-/* ------------------------------------------------------------------ */
-
-
-void geEnvelopeEditor::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 == G_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
-                       }
-               }
+/* -------------------------------------------------------------------------- */
+
 
+void geEnvelopeEditor::onRefreshAction() 
+{
+       Frame f = m_base->pixelToFrame((m_action->x() - x()) + geEnvelopePoint::SIDE / 2);
+       float v = yToValue(m_action->y() - y());
+       c::recorder::deleteEnvelopeAction(m_ch, m_action->a1, /*moved=*/true);
+       c::recorder::recordEnvelopeAction(m_ch, m_actionType, f, v);
+       rebuild();
 }
+}} // giada::v::
\ No newline at end of file
index b2218abbe592de78c24fbe3233d7e73323dfaf1f..0bdc8b574ec3c50c826d67e83daf287eb7dd1075 100644 (file)
@@ -1,11 +1,8 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
- * parent class of any envelope controller, from volume to VST parameter
- * automations.
- *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
+
 
 #ifndef GE_ENVELOPE_EDITOR_H
 #define GE_ENVELOPE_EDITOR_H
 
 
-#include <vector>
 #include "baseActionEditor.h"
 
 
-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() */
-
-       std::vector<point> points;
-
-       /* selectedPoint
-        * which point we are selecting? */
-
-       int selectedPoint;
+class SampleChannel;
 
-       /* draggedPoint
-        * which point we are dragging? */
 
-       int draggedPoint;
-
-       /* previousXPoint
-        * x coordinate of point at time t-1. Used to check effective shifts */
-
-       int previousXPoint;
+namespace giada {
+namespace v
+{
+class geEnvelopePoint;
 
-       void draw();
 
-       int handle(int e);
+class geEnvelopeEditor : public geBaseActionEditor
+{
+private:
 
-       int getSelectedPoint();
+       /* m_actionType
+       What type of action this envelope editor is dealing with. */
+       
+       int m_actionType;
 
-       void sortPoints();
+       void onAddAction()     override;
+       void onDeleteAction()  override;
+       void onMoveAction()    override;
+       void onResizeAction()  override{}; // Nothing to do here
+       void onRefreshAction() override;
 
-       /* 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. */
+       Pixel frameToX(Frame frame) const;
+       Pixel valueToY(float value) const;
+       float yToValue(Pixel pixel) const;
 
-       int verticalPoint(const point &p);
+       bool isFirstPoint() const;
+       bool isLastPoint()  const;
 
 public:
 
-       geEnvelopeEditor(int x, int y, gdActionEditor *pParent, int type, int range,
-    const char *l);
+       geEnvelopeEditor(Pixel x, Pixel y, int actionType, const char* l, SampleChannel* ch);
        ~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();
+       void draw() override;
 
-       inline void clearPoints() { points.clear(); }
+       void rebuild() override;
 };
+}} // giada::v::
 
 #endif
diff --git a/src/gui/elems/actionEditor/envelopePoint.cpp b/src/gui/elems/actionEditor/envelopePoint.cpp
new file mode 100644 (file)
index 0000000..a1f7e9e
--- /dev/null
@@ -0,0 +1,49 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/fl_draw.H>
+#include "../../../core/const.h"
+#include "envelopePoint.h"
+
+
+namespace giada {
+namespace v
+{
+geEnvelopePoint::geEnvelopePoint(Pixel X, Pixel Y, m::recorder::action a)
+       : geBaseAction(X, Y, SIDE, SIDE, /*resizable=*/false, a, {})
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geEnvelopePoint::draw()
+{
+       fl_rectf(x(), y(), w(), h(), hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1);
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/elems/actionEditor/envelopePoint.h b/src/gui/elems/actionEditor/envelopePoint.h
new file mode 100644 (file)
index 0000000..3e040ff
--- /dev/null
@@ -0,0 +1,52 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_ENVELOPE_POINT_H
+#define GE_ENVELOPE_POINT_H
+
+
+#include "../../../core/recorder.h"
+#include "baseAction.h"
+
+
+namespace giada {
+namespace v
+{
+class geEnvelopePoint : public geBaseAction
+{
+public:
+
+       static const Pixel SIDE = 12;
+
+       geEnvelopePoint(Pixel x, Pixel y, m::recorder::action a);
+
+       void draw() override;
+};
+}} // giada::v::
+
+
+#endif
index 4f17dbb12d1cda553fb52a3dcc971c1d44dca848..52cf3f1407b4af2b43df16687f9e7ceebd34f486 100644 (file)
 * --------------------------------------------------------------------------- */
 
 
-#include <cmath>
+#include <FL/Fl_Double_Window.H>
 #include "../../../core/conf.h"
-#include "../../../core/const.h"
 #include "../../../core/clock.h"
-#include "../../dialogs/gd_actionEditor.h"
+#include "../../../utils/math.h"
 #include "../basics/choice.h"
 #include "../basics/check.h"
-#include "actionEditor.h"
 #include "gridTool.h"
 
 
-using namespace giada::m;
-
-
-geGridTool::geGridTool(int x, int y, gdActionEditor *parent)
-       :       Fl_Group(x, y, 80, 20), parent(parent)
+namespace giada {
+namespace v
+{
+geGridTool::geGridTool(Pixel x, Pixel y)
+:      Fl_Group(x, y, 80, 20)
 {
        gridType = new geChoice(x, y, 40, 20);
        gridType->add("1");
@@ -54,10 +52,10 @@ geGridTool::geGridTool(int x, int y, gdActionEditor *parent)
        gridType->value(0);
        gridType->callback(cb_changeType, (void*)this);
 
-       active = new geCheck (x+44, y+4, 12, 12);
+       active = new geCheck(gridType->x() + gridType->w() + 4, y+4, 12, 12);
 
-       gridType->value(conf::actionEditorGridVal);
-       active->value(conf::actionEditorGridOn);
+       gridType->value(m::conf::actionEditorGridVal);
+       active->value(m::conf::actionEditorGridOn);
 
        end();
 }
@@ -68,31 +66,30 @@ geGridTool::geGridTool(int x, int y, gdActionEditor *parent)
 
 geGridTool::~geGridTool()
 {
-       conf::actionEditorGridVal = gridType->value();
-       conf::actionEditorGridOn  = active->value();
+       m::conf::actionEditorGridVal = gridType->value();
+       m::conf::actionEditorGridOn  = active->value();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geGridTool::cb_changeType(Fl_Widget *w, void *p)  { ((geGridTool*)p)->__cb_changeType(); }
+void geGridTool::cb_changeType(Fl_Widget *w, void *p) { ((geGridTool*)p)->cb_changeType(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geGridTool::__cb_changeType()
+void geGridTool::cb_changeType()
 {
-       calc();
-       parent->redraw();
+       window()->redraw();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-bool geGridTool::isOn()
+bool geGridTool::isOn() const
 {
        return active->value();
 }
@@ -101,7 +98,7 @@ bool geGridTool::isOn()
 /* -------------------------------------------------------------------------- */
 
 
-int geGridTool::getValue()
+int geGridTool::getValue() const
 {
        switch (gridType->value()) {
                case 0: return 1;
@@ -120,101 +117,19 @@ int geGridTool::getValue()
 /* -------------------------------------------------------------------------- */
 
 
-void geGridTool::calc()
-{
-       points.clear();
-       frames.clear();
-       bars.clear();
-       beats.clear();
-
-       /* find beats, bars and grid. The method is the same of the waveform in sample
-        * editor. Take totalwidth (the width in pixel of the area to draw), knowing
-        * that totalWidth = totalFrames / zoom. Then, for each pixel of totalwidth,
-        * put a concentrate of each block (which is totalFrames / zoom) */
-
-       int  j   = 0;
-       int fpgc = floor(clock::getFramesInBeat() / getValue());  // frames per grid cell
-
-       for (int i=1; i<parent->totalWidth; i++) {   // if i=0, step=0 -> useless cycle
-               int step = parent->zoom*i;
-               while (j < step && j < clock::getFramesInLoop()) {
-                       if (j % fpgc == 0) {
-                               points.push_back(i);
-                               frames.push_back(j);
-                       }
-                       if (j % clock::getFramesInBeat() == 0)
-                               beats.push_back(i);
-                       if (j % clock::getFramesInBar() == 0 && i != 1)
-                               bars.push_back(i);
-                       if (j == clock::getFramesInLoop() - 1)
-                               parent->coverX = i;
-                       j++;
-               }
-               j = step;
-       }
-
-       /* fix coverX if == 0, which means G_Mixer.beats == G_MAX_BEATS */
-
-       if (clock::getBeats() == G_MAX_BEATS)
-               parent->coverX = parent->totalWidth;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geGridTool::getSnapPoint(int v)
-{
-       if (v == 0) return 0;
-
-       for (int i=0; i<(int)points.size(); i++) {
-
-               if (i == (int) points.size()-1)
-                       return points.at(i);
-
-               int gp  = points.at(i);
-               int gpn = points.at(i+1);
-
-               if (v >= gp && v < gpn)
-                       return gp;
-       }
-       return v;  // default value
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geGridTool::getSnapFrame(int v)
+Frame geGridTool::getSnapFrame(Frame v) const
 {
-       v *= parent->zoom;  // transformation pixel -> frame
-
-       for (int i=0; i<(int)frames.size(); i++) {
-
-               if (i == (int) frames.size()-1)
-                       return frames.at(i);
-
-               int gf  = frames.at(i);     // grid frame
-               int gfn = frames.at(i+1);   // grid frame next
-
-               if (v >= gf && v < gfn) {
-
-                       /* which one is the closest? gf < v < gfn */
-
-                       if ((gfn - v) < (v - gf))
-                               return gfn;
-                       else
-                               return gf;
-               }
-       }
-       return v;  // default value
+       if (!isOn())
+               return v;
+       return u::math::quantize(v, getCellSize());
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int geGridTool::getCellSize()
+Frame geGridTool::getCellSize() const
 {
-       return (parent->coverX - parent->ac->x()) / clock::getBeats() / getValue();
+       return m::clock::getFramesInBeat() / getValue();
 }
+}} // giada::v::
\ No newline at end of file
index 2ca3eacb3a4b7b549799fd5a3d82e0816e67d9c5..f86e3d90370e5791b201f0ac744587e97afa4cc1 100644 (file)
 #define GE_GRID_TOOL_H
 
 
-#include <vector>
 #include <FL/Fl_Group.H>
+#include "../../../core/types.h"
 
 
 class geChoice;
 class geCheck;
-class gdActionEditor;
 
 
+namespace giada {
+namespace v
+{
 class geGridTool : public Fl_Group
 {
 private:
 
-  geChoice *gridType;
-       geCheck  *active;
-
-       gdActionEditor *parent;
+  geChoice* gridType;
+       geCheck*  active;
 
-       static void cb_changeType(Fl_Widget *w, void *p);
-       inline void __cb_changeType();
+       static void cb_changeType(Fl_Widget* w, void* p);
+       inline void cb_changeType();
 
 public:
 
-       geGridTool(int x, int y, gdActionEditor *parent);
+       geGridTool(Pixel x, Pixel y);
        ~geGridTool();
 
-       int  getValue();
-       bool isOn();
-       void calc();
+       int getValue() const;
+       bool isOn() const;
 
-       /* getSnapPoint
-        * given a cursor position in input, return the x coordinates of the
-        * nearest snap point (in pixel, clean, ie. not x()-shifted) */
-
-       int getSnapPoint(int v);
-       int getSnapFrame(int v);
+       Frame getSnapFrame(Frame f) const;
 
        /* getCellSize
-        * return the size in pixel of a single cell of the grid. */
-
-       int getCellSize();
+       Returns the size in frames of a single cell of the grid. */
 
-       std::vector<int> points;   // points of the grid
-       std::vector<int> frames;   // frames of the grid
+       Frame getCellSize() const;
 
-       std::vector<int> bars;
-       std::vector<int> beats;
 };
+}} // giada::v::
 
 
 #endif
diff --git a/src/gui/elems/actionEditor/muteEditor.cpp b/src/gui/elems/actionEditor/muteEditor.cpp
deleted file mode 100644 (file)
index 5ee61f2..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "../../../core/recorder.h"
-#include "../../../core/mixer.h"
-#include "../../../core/channel.h"
-#include "../../../core/clock.h"
-#include "../../../glue/main.h"
-#include "../../../utils/log.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "../../dialogs/gd_mainWindow.h"
-#include "../mainWindow/keyboard/keyboard.h"
-#include "gridTool.h"
-#include "muteEditor.h"
-
-
-extern gdMainWindow *G_MainWin;
-
-
-using namespace giada::m;
-
-
-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(G_COLOR_GREY_4);
-       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(G_COLOR_GREY_4);
-       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(G_COLOR_LIGHT_1);
-
-       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(G_COLOR_LIGHT_1);
-                       fl_rectf(pxNew-3, pyDot, 7, 7);
-                       fl_color(G_COLOR_LIGHT_1);
-               }
-               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 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 & (G_ACTION_MUTEON | G_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);
-                                       //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 >= clock::getFramesInLoop()) {
-                                               frame_b = clock::getFramesInLoop();
-                                               frame_a = frame_b-2048;
-                                       }
-
-                                       if (nextPoint % 2 != 0) {
-                                               recorder::rec(pParent->chan->index, G_ACTION_MUTEOFF, frame_a);
-                                               recorder::rec(pParent->chan->index, G_ACTION_MUTEON,  frame_b);
-                                       }
-                                       else {
-                                               recorder::rec(pParent->chan->index, G_ACTION_MUTEON,  frame_a);
-                                               recorder::rec(pParent->chan->index, G_ACTION_MUTEOFF, frame_b);
-                                       }
-          pParent->chan->hasActions = true;
-                                       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 == G_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);
-
-                                       recorder::deleteAction(pParent->chan->index, points.at(a).frame,
-          points.at(a).type, false, &mixer::mutex); // false = don't check vals
-                                       recorder::deleteAction(pParent->chan->index,    points.at(b).frame,
-          points.at(b).type, false, &mixer::mutex); // false = don't check vals
-          pParent->chan->hasActions = recorder::hasActions(pParent->chan->index);
-
-          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;
-
-                                       recorder::deleteAction(pParent->chan->index,
-            points.at(draggedPoint).frame, points.at(draggedPoint).type, false,
-            &mixer::mutex);  // don't check values
-          pParent->chan->hasActions = recorder::hasActions(pParent->chan->index);
-
-                                       recorder::rec(
-                                                       pParent->chan->index,
-                                                       points.at(draggedPoint).type,
-                                                       newFrame);
-
-          pParent->chan->hasActions = true;
-                                       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/actionEditor/muteEditor.h b/src/gui/elems/actionEditor/muteEditor.h
deleted file mode 100644 (file)
index d70bdd8..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_MUTE_TOOL_H
-#define GE_MUTE_TOOL_H
-
-
-#include <vector>
-#include "baseActionEditor.h"
-
-
-class gdActionEditor;
-
-
-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 */
-
-       std::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, 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
index b0608b2898e2de12fb401581aff2b9808d845913..0614b358ea9a4b90b967667b05af4674f28881e3 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <FL/fl_draw.H>
+#include <FL/Fl.H>
 #include "../../../core/const.h"
 #include "../../../core/conf.h"
-#include "../../../utils/log.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "pianoItem.h"
+#include "../../../core/midiChannel.h"
+#include "../../dialogs/actionEditor/midiActionEditor.h"
 #include "pianoRoll.h"
 #include "noteEditor.h"
 
 
-using namespace giada::m;
-
-
-geNoteEditor::geNoteEditor(int x, int y, gdActionEditor *pParent)
-  : Fl_Scroll(x, y, 200, 422),
-    pParent  (pParent)
+namespace giada {
+namespace v
+{
+geNoteEditor::geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base)
+: geScroll(x, y, 200, 422),
+       m_base  (base)
 {
-       size(pParent->totalWidth, conf::pianoRollH);
-       pianoRoll = new gePianoRoll(x, y, pParent->totalWidth, pParent);
+       pianoRoll = new gePianoRoll(x, y, m_base->fullWidth, static_cast<MidiChannel*>(m_base->ch));
+
+       rebuild();
+       
+       size(m_base->fullWidth, m::conf::pianoRollH);
+       
+       type(Fl_Scroll::VERTICAL_ALWAYS);
 }
 
 
@@ -52,39 +56,35 @@ geNoteEditor::geNoteEditor(int x, int y, gdActionEditor *pParent)
 
 geNoteEditor::~geNoteEditor()
 {
-       clear();
-       conf::pianoRollH = h();
-       conf::pianoRollY = pianoRoll->y();
+       m::conf::pianoRollH = h();
+       m::conf::pianoRollY = pianoRoll->y();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geNoteEditor::updateActions()
+void geNoteEditor::scroll()
 {
-       pianoRoll->updateActions();
-}
+       Pixel ey = Fl::event_y() - pianoRoll->pick;
 
+       Pixel y1 = y();
+       Pixel y2 = (y() + h()) - pianoRoll->h();
 
-/* -------------------------------------------------------------------------- */
+       if (ey > y1) ey = y1; else if (ey < y2) ey = y2;
 
+       pianoRoll->position(x(), ey);
 
-void geNoteEditor::draw()
-{
-       pianoRoll->size(this->w(), pianoRoll->h());  /// <--- not optimal
-
-       /* clear background */
+       redraw();
+}
 
-       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_1);
 
-       /* clip pianoRoll to pianoRollContainer size */
+/* -------------------------------------------------------------------------- */
 
-       fl_push_clip(x(), y(), w(), h());
-       draw_child(*pianoRoll);
-       fl_pop_clip();
 
-       fl_color(G_COLOR_GREY_4);
-       fl_line_style(0);
-       fl_rect(x(), y(), pParent->totalWidth, h());
+void geNoteEditor::rebuild()
+{
+       size(m_base->fullWidth, h());
+       pianoRoll->rebuild();
 }
+}} // giada::v::
\ No newline at end of file
index 26fbaf08482887a560e14d3f4e0c6624b65d57bd..130e92578747c139676c4485de40c4991316289f 100644 (file)
 #define GE_NOTE_EDITOR_H
 
 
-#include <FL/Fl_Scroll.H>
+#include "../basics/scroll.h"
 
 
-class gdActionEditor;
+namespace giada {
+namespace v
+{
+class gdMidiActionEditor;
 class gePianoRoll;
 
 
-class geNoteEditor : public Fl_Scroll
+class geNoteEditor : public geScroll
 {
 private:
 
-       gdActionEditor *pParent;
-       gePianoRoll    *pianoRoll;
+       gdMidiActionEditor* m_base;
 
 public:
 
-       geNoteEditor(int x, int y, gdActionEditor *parent);
+       geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base);
        ~geNoteEditor();
-       void draw();
-       void updateActions();
-};
 
+       void rebuild();
+       void scroll();
+
+       gePianoRoll* pianoRoll;
+};
+}} // giada::v::
 
 #endif
index 01e787ff1f539ccae6cde6e0e15248e6d2404c6e..5d0077a48df7d859e55adae93e2646bab03d943e 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include "../../../core/kernelMidi.h"
+#include <FL/fl_draw.H>
 #include "../../../core/const.h"
-#include "../../../core/mixer.h"
-#include "../../../core/channel.h"
-#include "../../../core/clock.h"
-#include "../../../core/midiChannel.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "noteEditor.h"
-#include "pianoRoll.h"
-#include "gridTool.h"
+#include "../../../core/midiEvent.h"
+#include "../../../utils/math.h"
 #include "pianoItem.h"
 
 
-using namespace giada::m;
-
-
-gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, recorder::action a,
-       recorder::action b, gdActionEditor* pParent)
-       : geBasePianoItem(X, Y, MIN_WIDTH, pParent),
-               a              (a),
-               b              (b),
-               changed        (false)
+namespace giada {
+namespace v
 {
-       int newX = rel_x + (a.frame / pParent->zoom);
-       int newY = rel_y + getY(kernelMidi::getB2(a.iValue));
-       int newW = (b.frame - a.frame) / pParent->zoom;
-       resize(newX, newY, newW, h());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoItem::reposition(int pianoRollX)
+gePianoItem::gePianoItem(Pixel X, Pixel Y, Pixel W, Pixel H, m::recorder::action a1,
+       m::recorder::action a2)
+: geBaseAction(X, Y, W, H, /*resizable=*/true, a1, a2),
+  orphaned    (a2.frame == -1)
 {
-       int newX = pianoRollX + (a.frame / pParent->zoom);
-       int newW = ((b.frame - a.frame) / pParent->zoom);
-       if (newW < MIN_WIDTH)
-               newW = MIN_WIDTH;
-       resize(newX, y(), newW, h());
-       redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-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* noteEditor = static_cast<geNoteEditor*>(parent());
-
-       for (int i=0; i<noteEditor->children(); i++) {
-
-               gePianoItem* pItem = static_cast<gePianoItem*>(noteEditor->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;
 }
 
 
@@ -105,192 +48,29 @@ bool gePianoItem::overlap()
 
 void gePianoItem::draw()
 {
-       int _w = w() > MIN_WIDTH ? w() : MIN_WIDTH;
-       fl_rectf(x(), y()+2, _w, h()-3, (Fl_Color) selected ? G_COLOR_LIGHT_1 : G_COLOR_LIGHT_1);
-}
-
-
-/* -------------------------------------------------------------------------- */
+       Fl_Color color = hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1;
 
+       Pixel by = y() + 2;
+       Pixel bh = h() - 3;
 
-void gePianoItem::removeAction()
-{
-       MidiChannel* ch = static_cast<MidiChannel*>(pParent->chan);
-       recorder::deleteAction(ch->index, a.frame, G_ACTION_MIDI, true,
-               &mixer::mutex, a.iValue, 0.0);
-       recorder::deleteAction(ch->index, b.frame, G_ACTION_MIDI, true,
-               &mixer::mutex, b.iValue, 0.0);
-
-       /* Send a note-off in case we are deleting it in a middle of a key_on/key_off
-       sequence. */
-
-       ch->sendMidi(b.iValue);
-       ch->hasActions = recorder::hasActions(ch->index);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gePianoItem::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()+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);
-                               removeAction();
-                               hide();   // for Windows
-                               Fl::delete_widget(this);
-                               static_cast<geNoteEditor*>(parent())->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
-
-               case FL_DRAG: {
-
-                       changed = true;
-
-                       geNoteEditor *pr = static_cast<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();
-                       static_cast<geNoteEditor*>(parent())->redraw();
-                       ret = 1;
-                       break;
-               }
-
-               case FL_RELEASE: {
-
-
-                       gePianoRoll* pianoRoll = static_cast<gePianoRoll*>(parent());
-
-                       /* Delete and record the action, only if it doesn't overlap with another 
-                       existing one. */
-
-                       if (overlap()) {
-                               resize(old_x, y(), old_w, h());
-                               redraw();
-                       }
-                       else
-                       if (changed) {
-                               removeAction();
-                               int note    = pianoRoll->yToNote(getRelY());
-                               int frame_a = getRelX() * pParent->zoom;
-                               int frame_b = (getRelX()+w()) * pParent->zoom;
-                               pianoRoll->recordAction(note, frame_a, frame_b);
-                               changed = false;
-                       }
-
-                       pianoRoll->redraw();
-
-                       ret = 1;
-                       break;
-               }
+       if (orphaned) {
+               fl_rect(x(), by, MIN_WIDTH, bh, color);
+               fl_line(x(), by, x() + MIN_WIDTH, by + bh);
+       }
+       else {
+               Pixel vh = calcVelocityH();
+               fl_rectf(x(), by + (bh - vh), w(), vh, color);
+               fl_rect(x(), by, w(), bh, color);
        }
-       return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gePianoItem::getRelY()
-{
-       return y() - parent()->y();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int gePianoItem::getRelX()
+Pixel gePianoItem::calcVelocityH() const
 {
-       return x() - parent()->x();
+       int v = m::MidiEvent(a1.iValue).getVelocity();
+       return u::math::map<int, Pixel>(v, 0, G_MAX_VELOCITY, 0, h() - 3);
 }
+}} // giada::v::
\ No newline at end of file
index a3a3f3abc44492920c72cb0ae272855ba5edb5fc..da7c614b665dd2ac98c319e3c96a81efec5ba6ef 100644 (file)
 
 
 #include "../../../core/recorder.h"
-#include "../../../core/midiEvent.h"
-#include "basePianoItem.h"
+#include "baseAction.h"
 
 
+namespace giada {
+namespace v
+{
 class gdActionEditor;
 
 
-class gePianoItem : public geBasePianoItem
+class gePianoItem : public geBaseAction
 {
 private:
 
-       struct giada::m::recorder::action a;
-       struct giada::m::recorder::action b;
-
-       int push_x;
-
-       /* 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;
-
-       /* getRelX/Y
-       Returns x/y point of this item, relative to piano roll (and not to entire 
-       screen). */
-
-       int getRelY();
-       int getRelX();
-
-       /* overlap
-       Checks if this item don't overlap with another one. */
-
-       bool overlap();
+       Pixel calcVelocityH() const;
 
 public:
 
-       static const int MIN_WIDTH    = 10;
-       static const int HANDLE_WIDTH = 5;
-
-       gePianoItem(int x, int y, int rel_x, int rel_y, 
-               struct giada::m::recorder::action a, struct giada::m::recorder::action b, 
-               gdActionEditor* pParent);
+       gePianoItem(int x, int y, int w, int h, m::recorder::action a1, 
+               m::recorder::action a2);
  
        void draw() override;
-       int handle(int e) override;
-
-  void reposition(int pianoRollX) override;
 
-       void removeAction();
+       bool orphaned;
 };
+}} // giada::v::
 
 
 #endif
diff --git a/src/gui/elems/actionEditor/pianoItemOrphaned.cpp b/src/gui/elems/actionEditor/pianoItemOrphaned.cpp
deleted file mode 100644 (file)
index 261d3b7..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "../../../core/const.h"
-#include "../../../core/kernelMidi.h"
-#include "../../../core/recorder.h"
-#include "../../../core/channel.h"
-#include "../../../core/midiChannel.h"
-#include "../../../core/mixer.h"
-#include "../../dialogs/gd_actionEditor.h"
-#include "pianoRoll.h"
-#include "noteEditor.h"
-#include "pianoItemOrphaned.h"
-
-
-using namespace giada::m;
-
-
-gePianoItemOrphaned::gePianoItemOrphaned(int x, int y, int xRel, int yRel,
-  recorder::action action, gdActionEditor* pParent)
-  : geBasePianoItem(x, y, WIDTH, pParent)
-{
-  note  = kernelMidi::getB2(action.iValue);
-  frame = action.frame;
-  event = action.iValue;
-  int newX = xRel + (frame / pParent->zoom);
-  int newY = yRel + getY(note);
-  resize(newX, newY, w(), h());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoItemOrphaned::reposition(int pianoRollX)
-{
-  int newX = pianoRollX + (frame / pParent->zoom);
-  resize(newX, y(), WIDTH, h());
-  redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gePianoItemOrphaned::handle(int e)
-{
-  int ret = geBasePianoItem::handle(e);
-  if (e == FL_PUSH) {
-    remove();
-    ret = 1;
-  }
-  return ret;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoItemOrphaned::remove()
-{
-  MidiChannel *ch = static_cast<MidiChannel*>(pParent->chan);
-  recorder::deleteAction(ch->index, frame, G_ACTION_MIDI, true, &mixer::mutex, 
-    event, 0.0);
-  hide();   // for Windows
-  Fl::delete_widget(this);
-  ch->hasActions = recorder::hasActions(ch->index);
-  static_cast<geNoteEditor*>(parent())->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoItemOrphaned::draw()
-{
-  fl_rect(x(), y()+2, WIDTH, h()-3, (Fl_Color) selected ? G_COLOR_LIGHT_1 : G_COLOR_LIGHT_1);
-}
diff --git a/src/gui/elems/actionEditor/pianoItemOrphaned.h b/src/gui/elems/actionEditor/pianoItemOrphaned.h
deleted file mode 100644 (file)
index b7d214c..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_PIANO_ITEM_ORPHANED_H
-#define GE_PIANO_ITEM_ORPHANED_H
-
-
-#include "../../../core/recorder.h"
-#include "basePianoItem.h"
-
-
-class gdActionEditor;
-
-
-class gePianoItemOrphaned : public geBasePianoItem
-{
-private:
-
-       int note;
-       int frame;
-       int event;
-
-public:
-
-  static const int WIDTH = 12;
-
-  gePianoItemOrphaned(int x, int y, int xRel, int yRel,
-    struct giada::m::recorder::action action, gdActionEditor* pParent);
-
-  void draw() override;
-  int handle(int e) override;
-
-  void reposition(int pianoRollX) override;
-
-  void remove();
-};
-
-
-#endif
index 346685261f894086b97e55b151a2ac0de91e1689..c1b416bad5facdf81e62462c2d918358c51bbe46 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
+#include <FL/Fl.H>
 #include "../../../core/conf.h"
 #include "../../../core/const.h"
-#include "../../../core/mixer.h"
 #include "../../../core/clock.h"
-#include "../../../core/channel.h"
-#include "../../../core/recorder.h"
-#include "../../../core/kernelMidi.h"
+#include "../../../core/midiChannel.h"
 #include "../../../utils/log.h"
 #include "../../../utils/string.h"
+#include "../../../utils/math.h"
 #include "../../../glue/recorder.h"
-#include "../../dialogs/gd_actionEditor.h"
+#include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "pianoItem.h"
-#include "pianoItemOrphaned.h"
 #include "noteEditor.h"
 #include "pianoRoll.h"
 
 
 using std::string;
 using std::vector;
-using namespace giada;
 
 
-gePianoRoll::gePianoRoll(int X, int Y, int W, gdActionEditor* pParent)
-       : geBaseActionEditor(X, Y, W, 40, pParent)
+namespace giada {
+namespace v
 {
-
-       resizable(nullptr);                   // don't resize children (i.e. pianoItem)
-       size(W, (MAX_KEYS+1) * CELL_H);      // 128 MIDI channels * CELL_H height
-
-       if (m::conf::pianoRollY == -1)
-               position(x(), y()-(h()/2));  // center
-       else
-               position(x(), m::conf::pianoRollY);
-
-       drawSurface1();
-       drawSurface2();
-
-       build();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoRoll::build()
+gePianoRoll::gePianoRoll(Pixel X, Pixel Y, Pixel W, MidiChannel* ch)
+       : geBaseActionEditor(X, Y, W, 40, ch),
+         pick              (0)
 {
-       using namespace m::recorder;
-       
-       clear();
-
-       int channel   = pParent->chan->index;
-       int maxSample = m::clock::getFramesInLoop();
-
-       vector<Composite> actions = c::recorder::getMidiActions(channel, maxSample); 
-       for (Composite composite : actions)
-       {
-               m::MidiEvent e1 = composite.a1.iValue;
-               m::MidiEvent e2 = composite.a2.iValue;
-
-               gu_log("[gePianoRoll] ((0x%X, 0x%X, f=%d) - (0x%X, 0x%X, f=%d))\n", 
-                       e1.getStatus(), e1.getNote(), composite.a1.frame,
-                       e2.getStatus(), e2.getNote(), composite.a2.frame
-               );
-
-               if (composite.a2.frame != -1)
-                       add(new gePianoItem(0, 0, x(), y(), composite.a1, composite.a2, pParent));
-               else
-                       add(new gePianoItemOrphaned(0, 0, x(), y(), composite.a1, pParent));
-       }
-
-       redraw();
+       position(x(), m::conf::pianoRollY == -1 ? y()-(h()/2) : m::conf::pianoRollY);
+       rebuild();
 }
 
 
@@ -107,8 +65,8 @@ 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 */
+       /* 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(), G_COLOR_GREY_1);
 
@@ -190,10 +148,12 @@ void gePianoRoll::drawSurface1()
 void gePianoRoll::drawSurface2()
 {
        surface2 = fl_create_offscreen(CELL_W, h());
+
        fl_begin_offscreen(surface2);
        fl_rectf(0, 0, CELL_W, h(), G_COLOR_GREY_1);
        fl_color(G_COLOR_GREY_3);
        fl_line_style(FL_DASH, 0, nullptr);
+
        for (int i=1; i<=MAX_KEYS+1; i++) {
                switch (i % KEYS) {
                        case (int) Notes::G:
@@ -209,6 +169,7 @@ void gePianoRoll::drawSurface2()
                        fl_line(0, i*CELL_H, CELL_W, i*CELL_H);
                }
        }
+
        fl_line_style(0);
        fl_end_offscreen();
 }
@@ -221,11 +182,11 @@ 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
+#if defined(__APPLE__) // TODO - is this still useful?
+       for (Pixel i=36; i<m_base->fullWidth; i+=36) /// TODO: i < ae->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
+       for (Pixel i=CELL_W; i<m_base->loopWidth; i+=CELL_W)
                fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 0, 0);
 #endif
 
@@ -239,93 +200,191 @@ void gePianoRoll::draw()
 
 int gePianoRoll::handle(int e)
 {
-       int ret = Fl_Group::handle(e);
-       switch (e) {
-               case FL_PUSH:   {
+       if (e == FL_PUSH && Fl::event_button3()) {
+               pick = Fl::event_y() - y();
+               return geBaseActionEditor::handle(e);
+       }
+       if (e == FL_DRAG && Fl::event_button3()) {
+               static_cast<geNoteEditor*>(parent())->scroll();
+               return 1;
+       }
+       return geBaseActionEditor::handle(e);
+}
 
-                       /* avoid click on grey area */
 
-                       if (Fl::event_x() >= pParent->coverX) {
-                               ret = 1;
-                               break;
-                       }
+/* -------------------------------------------------------------------------- */
 
-                       push_y = Fl::event_y() - y();
 
-                       if (Fl::event_button1()) {
+void gePianoRoll::onAddAction()
+{
+       Frame frame = m_base->pixelToFrame(Fl::event_x() - x());
+       int   note  = yToNote(Fl::event_y() - y());
+       c::recorder::recordMidiAction(m_ch->index, note, G_MAX_VELOCITY, frame);
+       
+       m_base->rebuild();  // Rebuild velocityEditor as well
+}
 
-                               /* 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;
+void gePianoRoll::onDeleteAction()
+{
+       c::recorder::deleteMidiAction(static_cast<MidiChannel*>(m_ch), m_action->a1, m_action->a2);     
+       
+       m_base->rebuild();  // Rebuild velocityEditor as well
+}
 
-                               /* If there are no pianoItems below the mouse, add a new one. */
 
-                               gePianoItem* pianoItem = dynamic_cast<gePianoItem*>(Fl::belowmouse());
-                               if (pianoItem == nullptr)
-                                       recordAction(yToNote(ay-y()), (ax-x()) * pParent->zoom);
-                       }
-                       ret = 1;
-                       break;
-               }
+/* -------------------------------------------------------------------------- */
 
-               case FL_DRAG:   {
 
-                       if (Fl::event_button3()) {
+void gePianoRoll::onMoveAction()
+{
+       /* Y computation:  - (CELL_H/2) is wrong: we should need the y pick value as 
+       done with x. Let's change this when vertical piano zoom will be available. */
 
-                               geNoteEditor* prc = static_cast<geNoteEditor*>(parent());
-                               position(x(), Fl::event_y() - push_y);
+       Pixel ex = Fl::event_x() - m_action->pick;
+       Pixel ey = snapToY(Fl::event_y() - y() - (CELL_H/2)) + y();
 
-                               if (y() > prc->y())
-                                       position(x(), prc->y());
-                               else
-                               if (y() < prc->y()+prc->h()-h())
-                                       position(x(), prc->y()+prc->h()-h());
+       Pixel x1 = x();
+       Pixel x2 = (m_base->loopWidth + x()) - m_action->w();
+       Pixel y1 = y();
+       Pixel y2 = y() + h();
 
-                               prc->redraw();
-                       }
-                       ret = 1;
-                       break;
-               }
+       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
 
-               case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
-                       ret = 1;
-                       break;
-               }
-       }
-       return ret;
+       m_action->position(ex, ey);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gePianoRoll::recordAction(int note, int frame_a, int frame_b)
+void gePianoRoll::onResizeAction()
 {
-       c::recorder::recordMidiAction(pParent->chan->index, note, frame_a, frame_b);
-       pParent->chan->hasActions = true;
-       build();
+       if (static_cast<gePianoItem*>(m_action)->orphaned)
+               return;
+
+       Pixel ex = Fl::event_x();
+
+       Pixel x1 = x();
+       Pixel x2 = m_base->loopWidth + x();
+       
+       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+
+       if (m_action->onRightEdge) 
+               m_action->setRightEdge(ex - m_action->x());
+       else
+               m_action->setLeftEdge(ex);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int gePianoRoll::yToNote(int y)
+void gePianoRoll::onRefreshAction()
+{
+       namespace cr = c::recorder;
+
+       if (static_cast<gePianoItem*>(m_action)->orphaned)
+               return;
+
+       Pixel p1 = m_action->x() - x();
+       Pixel p2 = m_action->x() + m_action->w() - x();
+
+       Frame f1 = 0;
+       Frame f2 = 0;
+
+       if (!m_action->isOnEdges()) {
+               f1 = m_base->pixelToFrame(p1);
+               f2 = m_base->pixelToFrame(p2, /*snap=*/false) - (m_base->pixelToFrame(p1, /*snap=*/false) - f1);
+       }       
+       else if (m_action->onLeftEdge) {
+               f1 = m_base->pixelToFrame(p1);
+               f2 = m_action->a2.frame;
+       }
+       else if (m_action->onRightEdge) {
+               f1 = m_action->a1.frame;
+               f2 = m_base->pixelToFrame(p2);
+       }
+
+       assert(f1 != 0 && f2 != 0);
+
+       int note     = yToNote(m_action->y() - y());
+       int velocity = m::MidiEvent(m_action->a1.iValue).getVelocity();
+
+       /* TODO - less then optimal. Let's wait for recorder refactoring... */
+       
+       int oldNote  = m::MidiEvent(m_action->a1.iValue).getNote();
+       cr::deleteMidiAction(static_cast<MidiChannel*>(m_ch), m_action->a1, m_action->a2);      
+       if (cr::midiActionCanFit(m_ch->index, note, f1, f2))
+               cr::recordMidiAction(m_ch->index, note, velocity, f1, f2);
+       else
+               cr::recordMidiAction(m_ch->index, oldNote, velocity, m_action->a1.frame, m_action->a2.frame);
+
+       m_base->rebuild();  // Rebuild velocityEditor as well
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoRoll::yToNote(Pixel p) const
+{
+       return gePianoRoll::MAX_KEYS - (p / gePianoRoll::CELL_H);
+}
+
+
+Pixel gePianoRoll::noteToY(int n) const
+{
+       return (MAX_KEYS * CELL_H) - (n * gePianoRoll::CELL_H);
+}
+
+
+Pixel gePianoRoll::snapToY(Pixel p) const
 {
-       return gePianoRoll::MAX_KEYS - (y / gePianoRoll::CELL_H);
+       return u::math::quantize(p, CELL_H);
 }
 
+
 /* -------------------------------------------------------------------------- */
 
 
-void gePianoRoll::updateActions()
+void gePianoRoll::rebuild()
 {
-       for (int k=0; k<children(); k++)
-               static_cast<geBasePianoItem*>(child(k))->reposition(x());
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       /* Remove all existing actions and set a new width, according to the current
+       zoom level. */
+
+       clear();
+       size(m_base->fullWidth, (MAX_KEYS + 1) * CELL_H);
+
+       vector<mr::Composite> actions = cr::getMidiActions(m_ch->index); 
+       for (mr::Composite comp : actions)
+       {
+               m::MidiEvent e1 = comp.a1.iValue;
+               m::MidiEvent e2 = comp.a2.iValue;
+
+               gu_log("[gePianoRoll::rebuild] ((0x%X, 0x%X, f=%d) - (0x%X, 0x%X, f=%d))\n", 
+                       e1.getStatus(), e1.getNote(), comp.a1.frame,
+                       e2.getStatus(), e2.getNote(), comp.a2.frame
+               );
+
+               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
+               Pixel py = y() + noteToY(e1.getNote());
+               Pixel pw = m_base->frameToPixel(comp.a2.frame - comp.a1.frame);
+               Pixel ph = CELL_H;
+
+               add(new gePianoItem(px, py, pw, ph, comp.a1, comp.a2));
+       }
+
+       drawSurface1();
+       drawSurface2();
+
+       redraw();
 }
+}} // giada::v::
\ No newline at end of file
index 59cf2193b9a11e716659cfcf34df981ac914fb53..1fdfbbcd3d37fa918226a87b02edcdf04a85cc33 100644 (file)
 #include "baseActionEditor.h"
 
 
-class gdActionEditor;
+class MidiChannel;
 
 
+namespace giada {
+namespace v
+{
 class gePianoRoll : public geBaseActionEditor
 {
 private:
@@ -46,11 +49,15 @@ private:
                A = 11, GS = 0
        };
 
-       int push_y;
-
        Fl_Offscreen surface1;  // notes, no repeat
        Fl_Offscreen surface2;  // lines, x-repeat
 
+       void onAddAction()     override;
+       void onDeleteAction()  override;
+       void onMoveAction()    override;
+       void onResizeAction()  override;
+       void onRefreshAction() override;
+
        /* 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
@@ -62,31 +69,28 @@ private:
        void drawSurface1();
        void drawSurface2();
 
-
-       void build();
+       Pixel snapToY(Pixel p) const;
+       int   yToNote(Pixel y) const;
+       Pixel noteToY(int n) const;
 
 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;
+       static const Pixel CELL_H    = 20;
+       static const Pixel CELL_W    = 40;
 
-       gePianoRoll(int x, int y, int w, gdActionEditor* pParent);
+       gePianoRoll(Pixel x, Pixel y, Pixel w, MidiChannel* ch);
 
        void draw() override;
        int  handle(int e) override;
 
-  /* updateActions
-  Repositions existing actions after a zoom gesture. */
-  
-       void updateActions() override;
-
-       void recordAction(int note, int frame_a, int frame_b=0);
+       void rebuild() override;
 
-       int yToNote(int y);
+       Pixel pick;
 };
+}} // giada::v::
 
 
 #endif
diff --git a/src/gui/elems/actionEditor/sampleAction.cpp b/src/gui/elems/actionEditor/sampleAction.cpp
new file mode 100644 (file)
index 0000000..f4e7d9b
--- /dev/null
@@ -0,0 +1,68 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/fl_draw.H>
+#include "../../../core/const.h"
+#include "../../../core/sampleChannel.h"
+#include "sampleAction.h"
+
+
+namespace giada {
+namespace v
+{
+geSampleAction::geSampleAction(Pixel X, Pixel Y, Pixel W, Pixel H, 
+       const SampleChannel* ch, m::recorder::action a1, m::recorder::action a2)
+: geBaseAction(X, Y, W, H, ch->mode == ChannelMode::SINGLE_PRESS, a1, a2),
+  m_ch        (ch)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleAction::draw()
+{
+       Fl_Color color = hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1; 
+
+       if (m_ch->mode == ChannelMode::SINGLE_PRESS) {
+               fl_rectf(x(), y(), w(), h(), color);
+       }
+       else {
+               if (a1.type == G_ACTION_KILL)
+                       fl_rect(x(), y(), MIN_WIDTH, h(), color);
+               else {
+                       fl_rectf(x(), y(), MIN_WIDTH, h(), color);
+                       if (a1.type == G_ACTION_KEYPRESS)
+                               fl_rectf(x()+3, y()+h()-11, w()-6, 8, G_COLOR_GREY_4);
+                       else
+                       if (a1.type == G_ACTION_KEYREL)
+                               fl_rectf(x()+3, y()+3, w()-6, 8, G_COLOR_GREY_4);
+               }
+       }
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/elems/actionEditor/sampleAction.h b/src/gui/elems/actionEditor/sampleAction.h
new file mode 100644 (file)
index 0000000..47a8116
--- /dev/null
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_SAMPLE_ACTION_H
+#define GE_SAMPLE_ACTION_H
+
+
+#include "../../../core/recorder.h"
+#include "baseAction.h"
+
+
+class SampleChannel;
+
+
+namespace giada {
+namespace v
+{
+class geSampleAction : public geBaseAction
+{
+private:
+
+       const SampleChannel* m_ch;
+
+public:
+
+       geSampleAction(Pixel x, Pixel y, Pixel w, Pixel h, const SampleChannel* ch,
+               m::recorder::action a1, m::recorder::action a2);
+
+       void draw() override;
+};
+}} // giada::v::
+
+
+#endif
diff --git a/src/gui/elems/actionEditor/sampleActionEditor.cpp b/src/gui/elems/actionEditor/sampleActionEditor.cpp
new file mode 100644 (file)
index 0000000..25bdd91
--- /dev/null
@@ -0,0 +1,222 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include "../../../core/const.h"
+#include "../../../core/conf.h"
+#include "../../../core/sampleChannel.h"
+#include "../../../utils/log.h"
+#include "../../../glue/recorder.h"
+#include "../../dialogs/actionEditor/baseActionEditor.h"
+#include "sampleAction.h"
+#include "sampleActionEditor.h"
+
+
+using std::vector;
+
+
+namespace giada {
+namespace v
+{
+geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, SampleChannel* ch)
+: geBaseActionEditor(x, y, 200, m::conf::sampleActionEditorH, ch)
+{
+       rebuild();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+geSampleActionEditor::~geSampleActionEditor()
+{
+       m::conf::sampleActionEditorH = h();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::rebuild()
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       const SampleChannel* ch = static_cast<const SampleChannel*>(m_ch);
+
+       /* Remove all existing actions and set a new width, according to the current
+       zoom level. */
+
+       clear();
+       size(m_base->fullWidth, h());
+
+       vector<mr::Composite> comps = cr::getSampleActions(ch);
+
+       for (mr::Composite comp : comps) {
+               gu_log("[geSampleActionEditor::rebuild] Action [%d, %d)\n", 
+                       comp.a1.frame, comp.a2.frame);
+               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
+               Pixel py = y() + 4;
+               Pixel pw = 0;
+               Pixel ph = h() - 8;
+               if (comp.a2.frame != -1)
+                               pw = m_base->frameToPixel(comp.a2.frame - comp.a1.frame);
+
+               geSampleAction* a = new geSampleAction(px, py, pw, ph, ch, comp.a1, comp.a2);
+               add(a);
+               resizable(a);
+       }
+
+       /* If channel is LOOP_ANY, deactivate it: a loop mode channel cannot hold 
+       keypress/keyrelease actions. */
+       
+       ch->isAnyLoopMode() ? deactivate() : activate();
+
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::draw()
+{
+       /* Draw basic boundaries (+ beat bars) and hide the unused area. Then draw 
+       children (the actions). */
+
+       baseDraw();
+
+       /* Print label. */
+
+       fl_color(G_COLOR_GREY_4);
+       fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
+       if (active())
+               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+       else
+               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+
+       draw_children();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::onAddAction()     
+{
+       Frame f = m_base->pixelToFrame(Fl::event_x() - x());
+       c::recorder::recordSampleAction(static_cast<SampleChannel*>(m_ch), 
+               m_base->getActionType(), f);
+       rebuild();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::onDeleteAction()  
+{
+       c::recorder::deleteSampleAction(static_cast<SampleChannel*>(m_ch), m_action->a1, m_action->a2);
+       rebuild();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::onMoveAction()    
+{
+       Pixel ex = Fl::event_x() - m_action->pick;
+
+       Pixel x1 = x();
+       Pixel x2 = m_base->loopWidth + x() - m_action->w();
+
+       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+
+       m_action->setPosition(ex);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::onResizeAction()  
+{
+       Pixel ex = Fl::event_x();
+
+       Pixel x1 = x();
+       Pixel x2 = m_base->loopWidth + x();
+
+       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+
+       if (m_action->onRightEdge) 
+               m_action->setRightEdge(ex - m_action->x());
+       else
+               m_action->setLeftEdge(ex);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geSampleActionEditor::onRefreshAction() 
+{
+       namespace cr = c::recorder;
+
+       SampleChannel* ch = static_cast<SampleChannel*>(m_ch);
+
+       Pixel p1   = m_action->x() - x();
+       Pixel p2   = m_action->x() + m_action->w() - x();
+       Frame f1   = 0;
+       Frame f2   = 0;
+       int   type = m_action->a1.type;
+
+       if (!m_action->isOnEdges()) {
+               f1 = m_base->pixelToFrame(p1);
+               f2 = m_base->pixelToFrame(p2, /*snap=*/false) - (m_base->pixelToFrame(p1, /*snap=*/false) - f1);
+       }       
+       else if (m_action->onLeftEdge) {
+               f1 = m_base->pixelToFrame(p1);
+               f2 = m_action->a2.frame;
+       }
+       else if (m_action->onRightEdge) {
+               f1 = m_action->a1.frame;
+               f2 = m_base->pixelToFrame(p2);
+       }
+
+       /* TODO - less then optimal. Let's wait for recorder refactoring... */
+
+       cr::deleteSampleAction(ch, m_action->a1, m_action->a2);
+       if (cr::sampleActionCanFit(ch, f1, f2))
+               cr::recordSampleAction(ch, type, f1, f2);
+       else
+               cr::recordSampleAction(ch, type, m_action->a1.frame, m_action->a2.frame);
+                               
+       rebuild();
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/elems/actionEditor/sampleActionEditor.h b/src/gui/elems/actionEditor/sampleActionEditor.h
new file mode 100644 (file)
index 0000000..197973f
--- /dev/null
@@ -0,0 +1,65 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_SAMPLE_ACTION_EDITOR_H
+#define GE_SAMPLE_ACTION_EDITOR_H
+
+
+#include "baseActionEditor.h"
+
+
+class SampleChannel;
+
+
+namespace giada {
+namespace v
+{
+class geSampleAction;
+
+
+class geSampleActionEditor : public geBaseActionEditor
+{
+private:
+
+       void onAddAction()     override;
+       void onDeleteAction()  override;
+       void onMoveAction()    override;
+       void onResizeAction()  override;
+       void onRefreshAction() override;
+
+public:
+
+       geSampleActionEditor(Pixel x, Pixel y, SampleChannel* ch);
+       ~geSampleActionEditor();
+
+       void draw() override;
+
+       void rebuild() override;
+};
+}} // giada::v::
+
+#endif
diff --git a/src/gui/elems/actionEditor/velocityEditor.cpp b/src/gui/elems/actionEditor/velocityEditor.cpp
new file mode 100644 (file)
index 0000000..faaefeb
--- /dev/null
@@ -0,0 +1,168 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include "../../../utils/log.h"
+#include "../../../utils/math.h"
+#include "../../../core/const.h"
+#include "../../../core/conf.h"
+#include "../../../core/clock.h"
+#include "../../../core/midiChannel.h"
+#include "../../../glue/recorder.h"
+#include "../../dialogs/actionEditor/baseActionEditor.h"
+#include "envelopePoint.h"
+#include "velocityEditor.h"
+
+
+using std::vector;
+
+
+namespace giada {
+namespace v
+{
+geVelocityEditor::geVelocityEditor(Pixel x, Pixel y, MidiChannel* ch)
+:      geBaseActionEditor(x, y, 200, m::conf::velocityEditorH, ch)
+{
+       rebuild();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+geVelocityEditor::~geVelocityEditor()
+{
+       m::conf::velocityEditorH = h();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geVelocityEditor::draw() 
+{
+       baseDraw();
+
+       /* Print label. */
+
+       fl_color(G_COLOR_GREY_4);
+       fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
+       fl_draw("Velocity", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT));
+
+       if (children() == 0)
+               return;
+
+       Pixel side = geEnvelopePoint::SIDE / 2;
+
+       for (int i=0; i<children(); i++) {
+               geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
+               if (m_action == nullptr)
+                       p->position(p->x(), valueToY(m::MidiEvent(p->a1.iValue).getVelocity()));
+               Pixel x1 = p->x() + side;
+               Pixel y1 = p->y();
+               Pixel y2 = y() + h();
+               fl_line(x1, y1, x1, y2);
+       }
+
+       draw_children();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+Pixel geVelocityEditor::valueToY(int v) const
+{
+       /* Cast the input type of 'v' to float, to make the mapping more precise. */
+       return u::math::map<float, Pixel>(v, 0, G_MAX_VELOCITY, y() + (h() - geEnvelopePoint::SIDE), y());
+}
+
+
+int geVelocityEditor::yToValue(Pixel px) const
+{
+       return u::math::map<Pixel, int>(px, h() - geEnvelopePoint::SIDE, 1, 0, G_MAX_VELOCITY); 
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geVelocityEditor::rebuild()
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       /* Remove all existing actions and set a new width, according to the current
+       zoom level. */
+
+       clear();
+       size(m_base->fullWidth, h());
+
+       vector<mr::Composite> actions = cr::getMidiActions(m_ch->index); 
+       for (mr::Composite comp : actions)
+       {
+               gu_log("[geVelocityEditor::rebuild] f=%d\n", comp.a1.frame);
+
+               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
+               Pixel py = y() + valueToY(m::MidiEvent(comp.a1.iValue).getVelocity());
+
+               add(new geEnvelopePoint(px, py, comp.a1));
+       }
+       
+       resizable(nullptr);
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geVelocityEditor::onMoveAction()    
+{
+       Pixel ey = Fl::event_y() - (geEnvelopePoint::SIDE / 2);
+
+       Pixel y1 = y();
+       Pixel y2 = y() + h() - geEnvelopePoint::SIDE;
+
+       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
+
+       m_action->position(m_action->x(), ey);
+       redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geVelocityEditor::onRefreshAction() 
+{
+       c::recorder::setVelocity(m_ch, m_action->a1, yToValue(m_action->y() - y()));
+
+       m_base->rebuild();  // Rebuild pianoRoll as well
+}
+}} // giada::v::
\ No newline at end of file
diff --git a/src/gui/elems/actionEditor/velocityEditor.h b/src/gui/elems/actionEditor/velocityEditor.h
new file mode 100644 (file)
index 0000000..40120c2
--- /dev/null
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GE_VELOCITY_EDITOR_H
+#define GE_VELOCITY_EDITOR_H
+
+
+#include "baseActionEditor.h"
+
+
+class MidiChannel;
+
+
+namespace giada {
+namespace v
+{
+class geEnvelopePoint;
+
+
+class geVelocityEditor : public geBaseActionEditor
+{
+private:
+
+       void onMoveAction()    override;
+       void onRefreshAction() override;
+       void onAddAction()     override{};
+       void onDeleteAction()  override{};
+       void onResizeAction()  override{};
+
+       Pixel valueToY(int v)   const;
+       int   yToValue(Pixel y) const;
+
+public:
+
+       geVelocityEditor(Pixel x, Pixel y, MidiChannel* ch);
+       ~geVelocityEditor();
+
+       void draw() override;
+
+       void rebuild() override;
+};
+}} // giada::v::
+
+
+#endif
index b35e0d0ba67b80cbccb7869570263939c062b7ed..527bfeb3d7716da14f24e1764435ef83c0b9ab90 100644 (file)
@@ -53,8 +53,7 @@ geTabMidi::geTabMidi(int X, int Y, int W, int H)
        system    = new geChoice(x()+w()-250, y()+9, 250, 20, "System");
        portOut   = new geChoice(x()+w()-250, system->y()+system->h()+8, 250, 20, "Output port");
        portIn    = new geChoice(x()+w()-250, portOut->y()+portOut->h()+8, 250, 20, "Input port");
-       noNoteOff = new geCheck (x()+w()-250, portIn->y()+portIn->h()+8, 230, 20, "Device does not send NoteOff");
-       midiMap   = new geChoice(x()+w()-250, noNoteOff->y()+noNoteOff->h(), 250, 20, "Output Midi Map");
+       midiMap   = new geChoice(x()+w()-250, portIn->y()+portIn->h()+8, 250, 20, "Output Midi Map");
        sync        = new geChoice(x()+w()-250, midiMap->y()+midiMap->h()+8, 250, 20, "Sync");
        new geBox(x(), sync->y()+sync->h()+8, w(), h()-150, "Restart Giada for the changes to take effect.");
        end();
@@ -69,8 +68,6 @@ geTabMidi::geTabMidi(int X, int Y, int W, int H)
        fetchInPorts();
        fetchMidiMaps();
 
-       noNoteOff->value(conf::noNoteOff);
-
        sync->add("(disabled)");
        sync->add("MIDI Clock (master)");
        sync->add("MTC (master)");
@@ -172,8 +169,6 @@ void geTabMidi::save()
 
        conf::midiPortOut = portOut->value()-1;   // -1 because midiPortOut=-1 is '(disabled)'
        conf::midiPortIn  = portIn->value()-1;    // -1 because midiPortIn=-1 is '(disabled)'
-
-       conf::noNoteOff   = noNoteOff->value();
        conf::midiMapPath = midimap::maps.size() == 0 ? "" : midiMap->text(midiMap->value());
 
        if      (sync->value() == 0)
@@ -221,13 +216,13 @@ void geTabMidi::fetchSystems()
 /* -------------------------------------------------------------------------- */
 
 
-void geTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((geTabMidi*)p)->__cb_changeSystem(); }
+void geTabMidi::cb_changeSystem(Fl_Widget* w, void* p) { ((geTabMidi*)p)->cb_changeSystem(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geTabMidi::__cb_changeSystem()
+void geTabMidi::cb_changeSystem()
 {
        /* if the user changes MIDI device (eg ALSA->JACK) device menu deactivates.
         * If it returns to the original system, we re-fill the list by
@@ -240,7 +235,6 @@ void geTabMidi::__cb_changeSystem()
                portIn->clear();
                fetchInPorts();
                portIn->activate();
-               noNoteOff->activate();
                sync->activate();
        }
        else {
@@ -252,7 +246,6 @@ void geTabMidi::__cb_changeSystem()
                portIn->clear();
                portIn->add("-- restart to fetch device(s) --");
                portIn->value(0);
-               noNoteOff->deactivate();
                sync->deactivate();
        }
 
index 8f0ee708f7b3c4f0cee0072b1612a218084e7f27..9b48a92b77748777e3c68771ddf9d943ea09e229 100644 (file)
@@ -45,19 +45,18 @@ private:
        void fetchInPorts();
        void fetchMidiMaps();
 
-       static void cb_changeSystem  (Fl_Widget *w, void *p);
-       inline void __cb_changeSystem();
+       static void cb_changeSystem(Fl_Widget* w, void* p);
+       inline void cb_changeSystem();
 
        int systemInitValue;
 
 public:
 
-       geChoice *system;
-       geChoice *portOut;
-       geChoice *portIn;
-       geCheck  *noNoteOff;
-       geChoice *midiMap;
-       geChoice *sync;
+       geChoice* system;
+       geChoice* portOut;
+       geChoice* portIn;
+       geChoice* midiMap;
+       geChoice* sync;
 
        geTabMidi(int x, int y, int w, int h);
 
index 44f8a08cba54399f442465ff8f009daf8a00d1e9..e47efb02d7f50a368260edea3c61514e20732563 100644 (file)
@@ -106,9 +106,8 @@ void geChannelMode::__cb_changeMode(int mode)
 {
   ch->mode = static_cast<ChannelMode>(mode);
 
-  /* what to do when the channel is playing and you change the mode?
-   * Nothing, since v0.5.3. Just refresh the action editor window, in
-   * case it's open */
+  /* What to do when the channel is playing and you change the mode? Nothing, 
+  since v0.5.3. Just refresh the action editor window, in case it's open. */
 
   gu_refreshActionEditor();
 }
index fb3860446b8d9a94edc6dd80fe5be07fc3168121..9c42a8ce3bed1596c286457a65f2ce6dfcfa9877 100644 (file)
 #include "../../../../glue/recorder.h"
 #include "../../../dialogs/gd_mainWindow.h"
 #include "../../../dialogs/channelNameInput.h"
-#include "../../../dialogs/gd_actionEditor.h"
 #include "../../../dialogs/gd_warnings.h"
 #include "../../../dialogs/gd_keyGrabber.h"
 #include "../../../dialogs/pluginList.h"
+#include "../../../dialogs/actionEditor/midiActionEditor.h"
 #include "../../../dialogs/midiIO/midiInputChannel.h"
 #include "../../../dialogs/midiIO/midiOutputMidiCh.h"
 #include "../../basics/boxtypes.h"
@@ -88,6 +88,8 @@ void menuCallback(Fl_Widget* w, void* v)
        using namespace giada;
 
        geMidiChannel* gch = static_cast<geMidiChannel*>(w);
+       MidiChannel*   ch  = static_cast<MidiChannel*>(gch->ch);
+
        Menu selectedItem = (Menu) (intptr_t) v;
 
        switch (selectedItem)
@@ -98,7 +100,7 @@ void menuCallback(Fl_Widget* w, void* v)
                case Menu::__END_RESIZE_SUBMENU__:
                        break;
                case Menu::EDIT_ACTIONS:
-                       gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+                       gu_openSubWindow(G_MainWin, new v::gdMidiActionEditor(ch), WID_ACTION_EDITOR);
                        break;
                case Menu::CLEAR_ACTIONS_ALL:
                        c::recorder::clearAllActions(gch);
@@ -110,8 +112,7 @@ void menuCallback(Fl_Widget* w, void* v)
                        gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
                        break;
                case Menu::SETUP_MIDI_OUTPUT:
-                       gu_openSubWindow(G_MainWin,
-                               new gdMidiOutputMidiCh(static_cast<MidiChannel*>(gch->ch)), 0);
+                       gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh(ch), 0);
                        break;
                case Menu::RESIZE_H1:
                        gch->changeSize(G_GUI_CHANNEL_H_1);
index b97d0f867ba8fbdac1702431a79b4baf885f7260..e82446fd10215a09275790aa85d26b3c6de1f9ea 100644 (file)
@@ -40,8 +40,8 @@
 #include "../../../dialogs/gd_keyGrabber.h"
 #include "../../../dialogs/sampleEditor.h"
 #include "../../../dialogs/channelNameInput.h"
-#include "../../../dialogs/gd_actionEditor.h"
 #include "../../../dialogs/gd_warnings.h"
+#include "../../../dialogs/actionEditor/sampleActionEditor.h"
 #include "../../../dialogs/browser/browserSave.h"
 #include "../../../dialogs/browser/browserLoad.h"
 #include "../../../dialogs/midiIO/midiOutputSampleCh.h"
@@ -78,7 +78,6 @@ enum class Menu
        EDIT_ACTIONS,
        CLEAR_ACTIONS,
        CLEAR_ACTIONS_ALL,
-       CLEAR_ACTIONS_MUTE,
        CLEAR_ACTIONS_VOLUME,
        CLEAR_ACTIONS_START_STOP,
        __END_CLEAR_ACTIONS_SUBMENU__,
@@ -103,6 +102,8 @@ void menuCallback(Fl_Widget* w, void* v)
        using namespace giada;
 
        geSampleChannel* gch = static_cast<geSampleChannel*>(w);
+       SampleChannel*   ch  = static_cast<SampleChannel*>(gch->ch);
+
        Menu selectedItem = (Menu) (intptr_t) v;
 
        switch (selectedItem) {
@@ -133,15 +134,15 @@ void menuCallback(Fl_Widget* w, void* v)
                        break;
                }
                case Menu::SETUP_MIDI_OUTPUT: {
-                       gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(static_cast<SampleChannel*>(gch->ch)), 0);
+                       gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(ch), 0);
                        break;
                }
                case Menu::EDIT_SAMPLE: {
-                       gu_openSubWindow(G_MainWin, new gdSampleEditor(static_cast<SampleChannel*>(gch->ch)), WID_SAMPLE_EDITOR);
+                       gu_openSubWindow(G_MainWin, new gdSampleEditor(ch), WID_SAMPLE_EDITOR);
                        break;
                }
                case Menu::EDIT_ACTIONS: {
-                       gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+                       gu_openSubWindow(G_MainWin, new v::gdSampleActionEditor(ch), WID_ACTION_EDITOR);
                        break;
                }
                case Menu::CLEAR_ACTIONS:
@@ -153,10 +154,6 @@ void menuCallback(Fl_Widget* w, void* v)
                        c::recorder::clearAllActions(gch);
                        break;
                }
-               case Menu::CLEAR_ACTIONS_MUTE: {
-                       c::recorder::clearMuteActions(gch);
-                       break;
-               }
                case Menu::CLEAR_ACTIONS_VOLUME: {
                        c::recorder::clearVolumeActions(gch);
                        break;
@@ -207,6 +204,8 @@ void menuCallback(Fl_Widget* w, void* v)
 }; // {namespace}
 
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 
@@ -313,7 +312,6 @@ void geSampleChannel::cb_openMenu()
                {"Edit actions...",          0, menuCallback, (void*) Menu::EDIT_ACTIONS},
                {"Clear actions",            0, menuCallback, (void*) Menu::CLEAR_ACTIONS, FL_SUBMENU},
                        {"All",        0, menuCallback, (void*) Menu::CLEAR_ACTIONS_ALL},
-                       {"Mute",       0, menuCallback, (void*) Menu::CLEAR_ACTIONS_MUTE},
                        {"Volume",     0, menuCallback, (void*) Menu::CLEAR_ACTIONS_VOLUME},
                        {"Start/Stop", 0, menuCallback, (void*) Menu::CLEAR_ACTIONS_START_STOP},
                        {0},
index 7e8bb19d3dc88ca05731640e1bb7a08cc9b1fa64..69b9628d7d13474bfc3295db1f82356d39f45c23 100644 (file)
 
 
 /* fl_xid() from FLTK returns a pointer to NSWindow, but plugins on OS X want a
- * pointer to NSView. The function does the hard conversion. */
+pointer to NSView. The function does the hard conversion. */
 
-void *cocoa_getViewFromWindow(void *p);
+void* cocoa_getViewFromWindow(void* p);
 
 /* A bug on on OS X seems to misalign plugins' UI. The function takes care of
- * fixing the positioning. */
+fixing the positioning. 
+TODO temporarily disabled: it does not work. */
 
-void cocoa_setWindowSize(void *p, int w, int h);
+//void cocoa_setWindowSize(void *p, int w, int h);
 
 
 #endif
index 69519e9fab3b4ddca81701d93e1722d1972a15c3..10792b1741632286affa9de70a0e6969f437a8da 100644 (file)
  #import "cocoa.h"
 
 
-void *cocoa_getViewFromWindow(void *p)
+void* cocoa_getViewFromWindow(void* p)
 {
-  NSWindow *win = (NSWindow *) p;
-  return (void*) [win contentView];
+  NSWindow* win = (NSWindow* ) p;
+  return (void*) win.contentView;
 }
 
-
+/*
 void cocoa_setWindowSize(void *p, int w, int h)
 {
   NSWindow *win = (NSWindow *) p;
   [win setContentSize:NSMakeSize(w, h)];
 }
+*/
\ No newline at end of file
index 39a856eafe96cd31f155f3af474d40d926a3c2d2..a481d690de753812f6171e021a22653f0aeef542 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <string>
+#include <FL/Fl.H>
 #include <FL/fl_draw.H>
 #if defined(_WIN32)
        #include "../ext/resource.h"
@@ -33,8 +34,6 @@
        #include <X11/xpm.h>
 #endif
 #include "../core/mixer.h"
-#include "../core/recorder.h"
-#include "../core/wave.h"
 #include "../core/clock.h"
 #include "../core/pluginHost.h"
 #include "../core/channel.h"
@@ -42,7 +41,7 @@
 #include "../core/graphics.h"
 #include "../gui/dialogs/gd_warnings.h"
 #include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/dialogs/gd_actionEditor.h"
+#include "../gui/dialogs/actionEditor/baseActionEditor.h"
 #include "../gui/dialogs/window.h"
 #include "../gui/dialogs/sampleEditor.h"
 #include "../gui/elems/mainWindow/mainIO.h"
 #include "gui.h"
 
 
-extern gdMainWindow *G_MainWin;
+extern gdMainWindowG_MainWin;
 
 
 using std::string;
+using namespace giada;
 using namespace giada::m;
+using namespace giada::v;
 
 
 static int blinker = 0;
@@ -180,21 +181,16 @@ void gu_openSubWindow(gdWindow* parent, gdWindow* child, int id)
 
 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);
-       }
+       gdBaseActionEditor* ae = static_cast<gdBaseActionEditor*>(G_MainWin->getChild(WID_ACTION_EDITOR));
+       if (ae != nullptr)
+               ae->rebuild();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-gdWindow *gu_getSubwindow(gdWindow *parent, int id)
+gdWindow* gu_getSubwindow(gdWindow* parent, int id)
 {
        if (parent->hasWindow(id))
                return parent->getChild(id);
@@ -221,19 +217,19 @@ void gu_closeAllSubwindows()
 /* -------------------------------------------------------------------------- */
 
 
-int gu_getStringWidth(const std::string &s)
+int gu_getStringWidth(const std::strings)
 {
-  int w = 0;
-  int h = 0;
-  fl_measure(s.c_str(), w, h);
-  return w;
+       int w = 0;
+       int h = 0;
+       fl_measure(s.c_str(), w, h);
+       return w;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-string gu_removeFltkChars(const string &s)
+string gu_removeFltkChars(const strings)
 {
        string out = gu_replace(s, "/", "-");
        out = gu_replace(out, "|", "-");
index 9bb7ca090cce1675e1798bea9ebb6b6194f9654a..324816bc92c48d3e09678caf4a180d0aee0a838f 100644 (file)
@@ -42,6 +42,17 @@ float linearToDB(float f)
 /* -------------------------------------------------------------------------- */
 
 
+int quantize(int x, int step)
+{
+       /* Source:
+       https://en.wikipedia.org/wiki/Quantization_(signal_processing)#Rounding_example */
+       return step * floor((x / (float) step) + 0.5f);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 float dBtoLinear(float f)
 {
        return std::pow(10, f/20.0f); 
index c17d82da703e403f535f7c7ed2732d56a4296385..16e6f9f83b6abc4d91be89cb94a96d4d150ea9aa 100644 (file)
@@ -35,15 +35,16 @@ namespace math
 {
 float linearToDB(float f);
 float dBtoLinear(float f);
+int quantize(int x, int step);
 
 /* map (template)
 Maps 'x' in range [a, b] to a new range [w, z]. Source:
        https://en.wikipedia.org/wiki/Linear_equation#Two-point_form*/
 
-template <typename T>
-T map(T x, T a, T b, T w, T z)
+template <typename Tin, typename Tout>
+Tout map(Tin x, Tin a, Tin b, Tout w, Tout z)
 {
-       return (((x - a) / (b - a)) * (z - w)) + w;
+       return (((x - a) / (float) (b - a)) * (z - w)) + w;
 }
 
 }}}  // giada::u::math::
index a51f216f050e4fa752d83cc88b9adfd0de0551ee..c392b812ca9637c7ab4d0ba9068be2f806f7fbe6 100644 (file)
@@ -28,7 +28,6 @@ TEST_CASE("conf")
     conf::midiSystem = 11;
     conf::midiPortOut = 12;
     conf::midiPortIn = 13;
-    conf::noNoteOff = false;
     conf::midiMapPath = "path/to/midi/map";
     conf::lastFileMap = "path/to/last/midi/map";
     conf::midiSync = 14;
@@ -104,7 +103,6 @@ TEST_CASE("conf")
     REQUIRE(conf::midiSystem == 11);
     REQUIRE(conf::midiPortOut == 12);
     REQUIRE(conf::midiPortIn == 13);
-    REQUIRE(conf::noNoteOff == false);
     REQUIRE(conf::midiMapPath == "path/to/midi/map");
     REQUIRE(conf::lastFileMap == "path/to/last/midi/map");
     REQUIRE(conf::midiSync == 14);
index c42e6b1b74617f0e68db33c464947b87c20f4ad1..85deb8982e39441a9eb90c739565e7eb3f78eaf1 100644 (file)
@@ -326,17 +326,17 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(0) == 0);
                REQUIRE(recorder::frames.at(1) == 80);
        }
-
+       
        SECTION("Test overdub, full overwrite")
        {
-               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF,  80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,  80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
 
                /* Should delete all actions in between and keep the first one, plus a
                new last action on frame 500. */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 1024);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 1024);
                recorder::stopOverdub(500, 500, &mutex);
 
                REQUIRE(recorder::frames.size() == 2);
@@ -344,22 +344,22 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(0) == 0);
                REQUIRE(recorder::frames.at(1) == 500);
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, left overlap")
        {
-               recorder::rec(0, G_ACTION_MUTEON,  100, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  100, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
 
                /* Overdub part of the leftmost part of a composite action. Expected result:
                a new composite action.
                Original:    ----|########|
                Overdub:     |#######|-----
                Result:      |#######|----- */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 16);
                recorder::stopOverdub(300, 500, &mutex);
 
                REQUIRE(recorder::frames.size() == 2);
@@ -368,22 +368,22 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(1) == 300);
 
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 300);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, right overlap")
        {
-               recorder::rec(0, G_ACTION_MUTEON,  000, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  000, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
 
                /* Overdub part of the rightmost part of a composite action. Expected result:
                a new composite action.
                Original:    |########|------
                Overdub:     -----|#######|--
                Result:      |###||#######|-- */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 100, 16);
                recorder::stopOverdub(500, 500, &mutex);
 
                REQUIRE(recorder::frames.size() == 4);
@@ -394,20 +394,20 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(3) == 500);
 
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
 
                REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(3).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, hole diggin'")
        {
-               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
 
                /* Overdub in the middle of a long, composite action. Expected result:
                original action trimmed down plus anther action next to it. Total frames
@@ -415,7 +415,7 @@ TEST_CASE("recorder")
                Original:    |#############|
                Overdub:     ---|#######|---
                Result:      |#||#######|--- */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 100, 16);
                recorder::stopOverdub(300, 500, &mutex);
 
                REQUIRE(recorder::frames.size() == 4);
@@ -426,27 +426,27 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(3) == 300);
 
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
 
                REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(3).at(0)->frame == 300);
-               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, cover all")
        {
-               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 100, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEON,  120, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEON,  220, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 100, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  120, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  220, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 300, 1, 0.5f);
 
                /* Overdub all existing actions. Expected result: a single composite one. */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 16);
                recorder::stopOverdub(500, 500, &mutex);
 
                REQUIRE(recorder::frames.size() == 2);
@@ -455,18 +455,18 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(1) == 500);
 
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, null loop")
        {
-               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 500, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 500, 1, 0.5f);
 
                /* A null loop is a loop that begins and ends on the very same frame. */
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 300, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 300, 16);
                recorder::stopOverdub(300, 700, &mutex);
 
                REQUIRE(recorder::frames.size() == 2);
@@ -474,9 +474,9 @@ TEST_CASE("recorder")
                REQUIRE(recorder::frames.at(1) == 284);  // 300 - bufferSize (16)
 
                REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
                REQUIRE(recorder::global.at(1).at(0)->frame == 284);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
        }
 
        SECTION("Test overdub, ring loop")
@@ -487,10 +487,10 @@ TEST_CASE("recorder")
                Overdub:     #####|------|##
                Result:      ---|#######||#| */
 
-               recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS,  200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL, 300, 1, 0.5f);
 
-               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 400, 16);
+               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 400, 16);
                recorder::stopOverdub(250, 700, &mutex);
 
                REQUIRE(recorder::frames.size() == 4);