New upstream version 0.14.3~dfsg1
authorJaromír Mikeš <mira.mikes@seznam.cz>
Mon, 2 Oct 2017 09:58:07 +0000 (11:58 +0200)
committerJaromír Mikeš <mira.mikes@seznam.cz>
Mon, 2 Oct 2017 09:58:07 +0000 (11:58 +0200)
45 files changed:
ChangeLog
Makefile.am
src/core/channel.cpp
src/core/const.h
src/core/mixer.cpp
src/core/mixerHandler.cpp
src/core/patch.cpp
src/core/patch.h
src/core/plugin.cpp
src/core/sampleChannel.cpp
src/core/waveFx.cpp
src/core/waveFx.h
src/core/waveManager.cpp
src/core/waveManager.h
src/glue/channel.cpp
src/glue/channel.h
src/glue/main.cpp
src/glue/sampleEditor.cpp
src/glue/sampleEditor.h
src/glue/storage.cpp
src/gui/dialogs/gd_actionEditor.cpp
src/gui/dialogs/gd_actionEditor.h
src/gui/dialogs/sampleEditor.cpp
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/basics/resizerBar.cpp
src/gui/elems/basics/resizerBar.h
src/gui/elems/mainWindow/keyboard/channel.cpp
src/gui/elems/mainWindow/keyboard/channel.h
src/gui/elems/mainWindow/keyboard/column.cpp
src/gui/elems/mainWindow/keyboard/column.h
src/gui/elems/mainWindow/keyboard/keyboard.cpp
src/gui/elems/mainWindow/keyboard/keyboard.h
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.h
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.h
src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp
src/gui/elems/sampleEditor/pitchTool.cpp
src/gui/elems/sampleEditor/rangeTool.cpp
src/gui/elems/sampleEditor/waveTools.cpp
src/gui/elems/sampleEditor/waveform.cpp
src/gui/elems/sampleEditor/waveform.h
src/utils/time.cpp [new file with mode: 0644]
src/utils/time.h [new file with mode: 0644]
tests/patch.cpp

index f9e8033e1b3314a8db0d69c922e94de249f79fb0..01102c86982ddda9cdb3ebc7b25e13af680efc9f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.14.3 --- 2017 . 09 . 18
+- [Sample Editor] New "reverse selection" function
+- [Sample Editor] New "normalize hard" function
+- [Sample Editor] New "copy to channel" function
+- [Sample Editor] Double click on waveform selects all
+- [Sample Editor] Fix garbled characters in window's title
+- [Sample Editor] Fix wrong result on "set pitch to song/bar"
+- Resizable channels
+- Remove calls to malloc/free in Mixer (use new/delete instead)
+- Improved UI management of VST plugins
+- Fix infinite loop for one shot retrig samples with quantizer > 0
+- Fix wrong geChannel count while saving a patch
+- Fix missing greyed-out options in Sample Channel's menu when loading a wrong
+  sample
+- Fix crash while audio recording with BPM set below the default 120 
+- Print correct octave numbers in Piano Roll
+
+
 0.14.2 --- 2017 . 08 . 14
 - [Sample Editor] Audible preview (with optional loop mode)
 - [Sample Editor] Frame-precise editing
index 6bdf82b1ed9779f8b89cc95a595a7427bcb8615c..2e2a260c841b490f4af41c6b2aea9f6ed2a954b0 100644 (file)
@@ -227,6 +227,8 @@ src/gui/elems/basics/radio.h           \
 src/gui/elems/basics/radio.cpp         \
 src/utils/log.h                        \
 src/utils/log.cpp                      \
+src/utils/time.h                       \
+src/utils/time.cpp                     \
 src/utils/math.h                       \
 src/utils/math.cpp                     \
 src/utils/gui.h                        \
index 5677f328558a09ef420a5e9f96e2a348dbecde57..d4bded3cb8b0c9e0e5b29d4da94dc9679c493e1b 100644 (file)
@@ -51,37 +51,37 @@ using namespace giada::m;
 
 Channel::Channel(int type, int status, int bufferSize)
 : bufferSize     (bufferSize),
-  midiFilter     (-1),
-  pan            (0.5f),
-  previewMode    (G_PREVIEW_NONE),
-  type           (type),
-  status         (status),
-  key            (0),
-  volume         (G_DEFAULT_VOL),
-  volume_i       (1.0f),
-  volume_d       (0.0f),
-  mute_i         (false),
-  mute_s         (false),
-  mute           (false),
-  solo           (false),
-  hasActions     (false),
+       midiFilter     (-1),
+       pan            (0.5f),
+       previewMode    (G_PREVIEW_NONE),
+       type           (type),
+       status         (status),
+       key            (0),
+       volume         (G_DEFAULT_VOL),
+       volume_i       (1.0f),
+       volume_d       (0.0f),
+       mute_i         (false),
+       mute_s         (false),
+       mute           (false),
+       solo           (false),
+       hasActions     (false),
        readActions    (false),
-  armed          (false),
-  recStatus      (REC_STOPPED),
-  vChan          (nullptr),
-  guiChannel     (nullptr),
-  midiIn         (true),
-  midiInKeyPress (0x0),
-  midiInKeyRel   (0x0),
-  midiInKill     (0x0),
-  midiInArm      (0x0),
-  midiInVolume   (0x0),
-  midiInMute     (0x0),
-  midiInSolo     (0x0),
-  midiOutL       (false),
-  midiOutLplaying(0x0),
-  midiOutLmute   (0x0),
-  midiOutLsolo   (0x0)
+       armed          (false),
+       recStatus      (REC_STOPPED),
+       vChan          (nullptr),
+       guiChannel     (nullptr),
+       midiIn         (true),
+       midiInKeyPress (0x0),
+       midiInKeyRel   (0x0),
+       midiInKill     (0x0),
+       midiInArm      (0x0),
+       midiInVolume   (0x0),
+       midiInMute     (0x0),
+       midiInSolo     (0x0),
+       midiOutL       (false),
+       midiOutLplaying(0x0),
+       midiOutLmute   (0x0),
+       midiOutLsolo   (0x0)
 {
 }
 
@@ -117,49 +117,49 @@ bool Channel::allocBuffers()
 
 void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
 {
-  key             = src->key;
-  volume          = src->volume;
-  volume_i        = src->volume_i;
-  volume_d        = src->volume_d;
-  pan             = src->pan;
-  mute_i          = src->mute_i;
-  mute_s          = src->mute_s;
-  mute            = src->mute;
-  solo            = src->solo;
-  hasActions      = src->hasActions;
-  recStatus       = src->recStatus;
-  midiIn          = src->midiIn;
-  midiInKeyPress  = src->midiInKeyPress;
-  midiInKeyRel    = src->midiInKeyRel;
-  midiInKill      = src->midiInKill;
-  midiInArm       = src->midiInArm;
-  midiInVolume    = src->midiInVolume;
-  midiInMute      = src->midiInMute;
-  midiInSolo      = src->midiInSolo;
-  midiOutL        = src->midiOutL;
-  midiOutLplaying = src->midiOutLplaying;
-  midiOutLmute    = src->midiOutLmute;
-  midiOutLsolo    = src->midiOutLsolo;
-
-  /* clone plugins */
+       key             = src->key;
+       volume          = src->volume;
+       volume_i        = src->volume_i;
+       volume_d        = src->volume_d;
+       pan             = src->pan;
+       mute_i          = src->mute_i;
+       mute_s          = src->mute_s;
+       mute            = src->mute;
+       solo            = src->solo;
+       hasActions      = src->hasActions;
+       recStatus       = src->recStatus;
+       midiIn          = src->midiIn;
+       midiInKeyPress  = src->midiInKeyPress;
+       midiInKeyRel    = src->midiInKeyRel;
+       midiInKill      = src->midiInKill;
+       midiInArm       = src->midiInArm;
+       midiInVolume    = src->midiInVolume;
+       midiInMute      = src->midiInMute;
+       midiInSolo      = src->midiInSolo;
+       midiOutL        = src->midiOutL;
+       midiOutLplaying = src->midiOutLplaying;
+       midiOutLmute    = src->midiOutLmute;
+       midiOutLsolo    = src->midiOutLsolo;
+
+       /* clone plugins */
 
 #ifdef WITH_VST
-  for (unsigned i=0; i<src->plugins.size(); i++)
-    pluginHost::clonePlugin(src->plugins.at(i), pluginHost::CHANNEL,
-      pluginMutex, this);
+       for (unsigned i=0; i<src->plugins.size(); i++)
+               pluginHost::clonePlugin(src->plugins.at(i), pluginHost::CHANNEL,
+                       pluginMutex, this);
 #endif
 
-  /* clone actions */
-
-  for (unsigned i=0; i<recorder::global.size(); i++) {
-    for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-      recorder::action *a = recorder::global.at(i).at(k);
-      if (a->chan == src->index) {
-        recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
-        hasActions = true;
-      }
-    }
-  }
+       /* clone actions */
+
+       for (unsigned i=0; i<recorder::global.size(); i++) {
+               for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
+                       recorder::action *a = recorder::global.at(i).at(k);
+                       if (a->chan == src->index) {
+                               recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
+                               hasActions = true;
+                       }
+               }
+       }
 }
 
 
@@ -200,8 +200,9 @@ int Channel::writePatch(int i, bool isProject)
 {
        patch::channel_t pch;
        pch.type            = type;
-       pch.key             = key;
        pch.index           = index;
+       pch.size            = guiChannel->getSize();
+       pch.key             = key;
        pch.column          = guiChannel->getColumnIndex();
        pch.mute            = mute;
        pch.mute_s          = mute_s;
@@ -227,9 +228,9 @@ int Channel::writePatch(int i, bool isProject)
                        if (action->chan == index) {
                                patch::action_t pac;
                                pac.type   = action->type;
-                   pac.frame  = action->frame;
-                   pac.fValue = action->fValue;
-                   pac.iValue = action->iValue;
+                               pac.frame  = action->frame;
+                               pac.fValue = action->fValue;
+                               pac.iValue = action->iValue;
                                pch.actions.push_back(pac);
                        }
                }
@@ -242,7 +243,7 @@ int Channel::writePatch(int i, bool isProject)
                Plugin *pPlugin = pluginHost::getPluginByIndex(i, pluginHost::CHANNEL, this);
                patch::plugin_t pp;
                pp.path   = pPlugin->getUniqueId();
-    pp.bypass = pPlugin->isBypassed();
+               pp.bypass = pPlugin->isBypassed();
                for (int k=0; k<pPlugin->getNumParameters(); k++)
                        pp.params.push_back(pPlugin->getParameter(k));
                for (unsigned k=0; k<pPlugin->midiInParams.size(); k++)
@@ -262,7 +263,7 @@ int Channel::writePatch(int i, bool isProject)
 
 
 int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
-  int samplerate, int rsmpQuality)
+       int samplerate, int rsmpQuality)
 {
        int ret = 1;
        patch::channel_t *pch = &patch::channels.at(i);
@@ -277,10 +278,10 @@ int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
        midiIn          = pch->midiIn;
        midiInKeyPress  = pch->midiInKeyPress;
        midiInKeyRel    = pch->midiInKeyRel;
-  midiInKill      = pch->midiInKill;
-  midiInVolume    = pch->midiInVolume;
-  midiInMute      = pch->midiInMute;
-  midiInSolo      = pch->midiInSolo;
+       midiInKill      = pch->midiInKill;
+       midiInVolume    = pch->midiInVolume;
+       midiInMute      = pch->midiInMute;
+       midiInSolo      = pch->midiInSolo;
        midiOutL        = pch->midiOutL;
        midiOutLplaying = pch->midiOutLplaying;
        midiOutLmute    = pch->midiOutLmute;
@@ -289,7 +290,7 @@ int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
        for (unsigned k=0; k<pch->actions.size(); k++) {
                patch::action_t *ac = &pch->actions.at(k);
                recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue);
-    hasActions = true;
+               hasActions = true;
        }
 
 #ifdef WITH_VST
@@ -297,17 +298,17 @@ int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
        for (unsigned k=0; k<pch->plugins.size(); k++) {
                patch::plugin_t *ppl = &pch->plugins.at(k);
                Plugin *plugin = pluginHost::addPlugin(ppl->path, pluginHost::CHANNEL,
-      pluginMutex, this);
-    if (plugin == nullptr) {
-      ret &= 0;
-      continue;
-    }
+                       pluginMutex, this);
+               if (plugin == nullptr) {
+                       ret &= 0;
+                       continue;
+               }
                plugin->setBypass(ppl->bypass);
                for (unsigned j=0; j<ppl->params.size(); j++)
                        plugin->setParameter(j, ppl->params.at(j));
-    plugin->midiInParams.clear();
-    for (unsigned j=0; j<ppl->midiInParams.size(); j++)
-      plugin->midiInParams.push_back(ppl->midiInParams.at(j));
+               plugin->midiInParams.clear();
+               for (unsigned j=0; j<ppl->midiInParams.size(); j++)
+                       plugin->midiInParams.push_back(ppl->midiInParams.at(j));
                ret &= 1;
        }
 
@@ -380,19 +381,19 @@ void Channel::receiveMidi(uint32_t msg)
 
 void Channel::setPan(float v)
 {
-  if (v > 1.0f)
-    pan = 1.0f;
-  else 
-  if (v < 0.0f)
-    pan = 0.0f;
-  else
-    pan = v;
+       if (v > 1.0f)
+               pan = 1.0f;
+       else 
+       if (v < 0.0f)
+               pan = 0.0f;
+       else
+               pan = v;
 }
 
 
 float Channel::getPan()
 {
-  return pan;
+       return pan;
 }
 
 
@@ -401,12 +402,12 @@ float Channel::getPan()
 
 float Channel::calcPanning(int ch)
 {
-  if (pan == 0.5f) // center: nothing to do
-    return 1.0;
-  if (ch == 0)
-    return 1.0 - pan;
-  else  // channel 1
-    return pan; 
+       if (pan == 0.5f) // center: nothing to do
+               return 1.0;
+       if (ch == 0)
+               return 1.0 - pan;
+       else  // channel 1
+               return pan; 
 }
 
 
@@ -432,7 +433,7 @@ bool Channel::isPreview()
 
 juce::MidiBuffer &Channel::getPluginMidiEvents()
 {
-  return midiBuffer;
+       return midiBuffer;
 }
 
 
@@ -441,7 +442,7 @@ juce::MidiBuffer &Channel::getPluginMidiEvents()
 
 void Channel::clearMidiBuffer()
 {
-  midiBuffer.clear();
+       midiBuffer.clear();
 }
 
 
index ad5384a728289290a921c0a021eb735bce291319..3d3c223b2780b8e3a858543533175afbce56560b 100644 (file)
 
 /* -- version --------------------------------------------------------------- */
 #define G_APP_NAME      "Giada"
-#define G_VERSION_STR   "0.14.2"
+#define G_VERSION_STR   "0.14.3"
 #define G_VERSION_MAJOR 0
 #define G_VERSION_MINOR 14
-#define G_VERSION_PATCH 2
+#define G_VERSION_PATCH 3
 
 #define CONF_FILENAME "giada.conf"
 
 #define G_GUI_HEIGHT                      510
 #define G_GUI_PLUGIN_RATE    0.05  // refresh rate for plugin GUIs
 #define G_GUI_FONT_SIZE_BASE 12
+#define G_GUI_INNER_MARGIN   4
+#define G_GUI_OUTER_MARGIN   8
+#define G_GUI_UNIT           20    // base unit for elements 
+#define G_GUI_CHANNEL_H_1    G_GUI_UNIT
+#define G_GUI_CHANNEL_H_2    G_GUI_UNIT * 2
+#define G_GUI_CHANNEL_H_3    G_GUI_UNIT * 4
+#define G_GUI_CHANNEL_H_4    G_GUI_UNIT * 6
+
 
 #define G_COLOR_RED       fl_rgb_color(28,  32,  80)
 #define G_COLOR_BLUE      fl_rgb_color(113, 31,  31)
 #define G_COLOR_RED_ALERT fl_rgb_color(239, 75,  53)
 
-#define G_COLOR_LIGHT_2 fl_rgb_color(200, 200, 200)
-#define G_COLOR_LIGHT_1 fl_rgb_color(170, 170, 170)
-#define G_COLOR_GREY_4  fl_rgb_color(78,  78,  78)
-#define G_COLOR_GREY_3  fl_rgb_color(54,  54,  54)
-#define G_COLOR_GREY_2  fl_rgb_color(37,  37,  37)
-#define G_COLOR_GREY_1  fl_rgb_color(25,  25,  25)
-#define G_COLOR_BLACK   fl_rgb_color(0,   0,   0)
+#define G_COLOR_LIGHT_2  fl_rgb_color(200, 200, 200)
+#define G_COLOR_LIGHT_1  fl_rgb_color(170, 170, 170)
+#define G_COLOR_GREY_4   fl_rgb_color(78,  78,  78)
+#define G_COLOR_GREY_3   fl_rgb_color(54,  54,  54)
+#define G_COLOR_GREY_2   fl_rgb_color(37,  37,  37)
+#define G_COLOR_GREY_1_5 fl_rgb_color(28,  28,  28)
+#define G_COLOR_GREY_1   fl_rgb_color(25,  25,  25)
+#define G_COLOR_BLACK    fl_rgb_color(0,   0,   0)
 
 
 
 #define G_MAX_BEATS                              32
 #define G_MAX_BARS                               32
 #define G_MAX_QUANTIZE      8
-#define G_MAX_PATCHNAME_LEN    32
 #define G_MIN_DB_SCALE      60.0f
 #define G_MIN_COLUMN_WIDTH  140
 #define G_MAX_BOOST_DB      20.0f
 #define G_DEFAULT_MIDI_PORT_IN   -1
 #define G_DEFAULT_MIDI_PORT_OUT  -1
 #define G_DEFAULT_SAMPLERATE      44100
-#define G_DEFAULT_BUFSIZE                    1024
-#define G_DEFAULT_DELAYCOMP                0
+#define G_DEFAULT_BUFSIZE         1024
+#define G_DEFAULT_DELAYCOMP       0
 #define G_DEFAULT_BIT_DEPTH       32     // float
 #define G_DEFAULT_AUDIO_CHANS     2      // stereo for internal processing
 #define G_DEFAULT_VOL             1.0f
@@ -350,6 +358,7 @@ const int MIDI_CHANS[16] = {
 #define PATCH_KEY_CHANNELS                     "channels"
 #define PATCH_KEY_CHANNEL_TYPE                 "type"
 #define PATCH_KEY_CHANNEL_INDEX                "index"
+#define PATCH_KEY_CHANNEL_SIZE                 "size"
 #define PATCH_KEY_CHANNEL_COLUMN               "column"
 #define PATCH_KEY_CHANNEL_MUTE                 "mute"
 #define PATCH_KEY_CHANNEL_MUTE_S               "mute_s"
index 09927dcce344c16bbe6a7cb97e41619337a2a500..e86595ddbae2d30e56aec77c7de9cbcc4925d8f2 100644 (file)
@@ -53,24 +53,24 @@ namespace
 
 
 float tock[TICKSIZE] = {
-  0.059033,  0.117240,  0.173807,  0.227943,  0.278890,  0.325936,
-  0.368423,  0.405755,  0.437413,  0.462951,  0.482013,  0.494333,
-  0.499738,  0.498153,  0.489598,  0.474195,  0.452159,  0.423798,
-  0.389509,  0.349771,  0.289883,  0.230617,  0.173194,  0.118739,
-  0.068260,  0.022631, -0.017423, -0.051339,   -0.078721, -0.099345,
+       0.059033,  0.117240,  0.173807,  0.227943,  0.278890,  0.325936,
+       0.368423,  0.405755,  0.437413,  0.462951,  0.482013,  0.494333,
+       0.499738,  0.498153,  0.489598,  0.474195,  0.452159,  0.423798,
+       0.389509,  0.349771,  0.289883,  0.230617,  0.173194,  0.118739,
+       0.068260,  0.022631, -0.017423, -0.051339,      -0.078721, -0.099345,
  -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
  -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,
-  0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
+       0.175860,  0.341914,  0.488904,  0.608633,  0.694426,  0.741500,
+       0.747229,  0.711293,    0.635697,  0.524656,  0.384362,  0.222636,
+       0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
  -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
  -0.201360, -0.067752,  0.052194,  0.151746,  0.226280,  0.273493,
-  0.293425,  0.288307,  0.262252,  0.220811,  0.170435,  0.117887,
-  0.069639,  0.031320
+       0.293425,  0.288307,  0.262252,  0.220811,  0.170435,  0.117887,
+       0.069639,  0.031320
 };
 
 
@@ -83,7 +83,7 @@ Records from line in. */
 void lineInRec(float* inBuf, unsigned frame)
 {
        if (!mh::hasArmedSampleChannels() || !kernelAudio::isInputEnabled() || !recording)
-               return;
+               return;
 
        /* Delay comp: wait until waitRec reaches delayComp. WaitRec
         * returns to 0 in mixerHandler, as soon as the recording ends */
@@ -157,7 +157,7 @@ void readActions(unsigned frame)
                                int index   = recorder::global.at(i).at(j)->chan;
                                Channel *ch = mh::getChannelByIndex(index);
                                ch->parseAction(recorder::global.at(i).at(j), frame,
-          clock::getCurrentFrame(), clock::getQuantize(), clock::isRunning());
+                                       clock::getCurrentFrame(), clock::getQuantize(), clock::isRunning());
                        }
                        break;
                }
@@ -173,10 +173,10 @@ Computes quantization on 'rewind' button and all channels. */
 
 void doQuantize(unsigned frame)
 {
-  /* Nothing to do if quantizer disabled or a quanto has not passed yet. */
+       /* Nothing to do if quantizer disabled or a quanto has not passed yet. */
 
-  if (clock::getQuantize() == 0 || !clock::quantoHasPassed())
-    return;
+       if (clock::getQuantize() == 0 || !clock::quantoHasPassed())
+               return;
        if (rewindWait) {
                rewindWait = false;
                rewind();
@@ -349,9 +349,9 @@ void testFirstBeat(unsigned frame)
 
 void testLastBeat()
 {
-  if (clock::isOnBeat())
-    if (metronome && !tickPlay)
-      tockPlay = true;
+       if (clock::isOnBeat())
+               if (metronome && !tickPlay)
+                       tockPlay = true;
 }
 
 }; // {anonymous}
@@ -404,11 +404,15 @@ void init(int framesInSeq, int audioBufferSize)
        /* Allocate virtual input channels. vChanInput has variable size: it depends
        on how many frames there are in sequencer. */
 
-  allocVirtualInput(framesInSeq);
+       allocVirtualInput(framesInSeq);
 
-  if (vChanInToOut != nullptr)
-    free(vChanInToOut);
-       vChanInToOut = (float*) malloc(audioBufferSize * 2 * sizeof(float));
+       if (vChanInToOut != nullptr)
+               delete[] vChanInToOut;
+       vChanInToOut = new (std::nothrow) float[audioBufferSize * 2];
+       if (!vChanInToOut) {
+               gu_log("[Mixer::init] vChanInToOut alloc error!\n");    
+               return;
+       }
 
        pthread_mutex_init(&mutex_recs, nullptr);
        pthread_mutex_init(&mutex_chans, nullptr);
@@ -424,10 +428,11 @@ void init(int framesInSeq, int audioBufferSize)
 void allocVirtualInput(int frames)
 {
        if (vChanInput != nullptr)
-               free(vChanInput);
-       vChanInput = (float*) malloc(frames * sizeof(float));
+               delete[] vChanInput;
+       vChanInput = new (std::nothrow) float[frames];
        if (!vChanInput)
-               gu_log("[Mixer] vChanInput realloc error!\n");  
+               gu_log("[Mixer::allocVirtualInput] vChanInput realloc error!\n");       
+       gu_log("[Mixer::allocVirtualInput] vChanInput ready, %d frames\n", frames);     
 }
 
 
@@ -441,7 +446,7 @@ int masterPlay(void* _outBuf, void* _inBuf, unsigned bufferSize,
                return 0;
 
 #ifdef __linux__
-  clock::recvJackSync();
+       clock::recvJackSync();
 #endif
 
        float* outBuf = (float*) _outBuf;
@@ -521,7 +526,7 @@ bool isSilent()
 
 void rewind()
 {
-  clock::rewind();
+       clock::rewind();
        if (clock::isRunning())
                for (unsigned i=0; i<channels.size(); i++)
                        channels.at(i)->rewind();
index 4de62d083424a19b558c3aaa0a7d62749a8501f2..623ed27f64f0cd3d7b582ff00d590198623de527 100644 (file)
@@ -69,7 +69,7 @@ int readPatchPlugins(vector<patch::plugin_t> *list, int type)
        int ret = 1;
        for (unsigned i=0; i<list->size(); i++) {
                patch::plugin_t *ppl = &list->at(i);
-    // TODO use glue_addPlugin()
+               // TODO use glue_addPlugin()
                Plugin *plugin = pluginHost::addPlugin(ppl->path.c_str(), type,
                                &mixer::mutex_plugins, nullptr);
                if (plugin != nullptr) {
@@ -135,7 +135,7 @@ bool uniqueSampleName(SampleChannel* ch, const string& name)
 
 Channel* addChannel(int type)
 {
-  Channel* ch;
+       Channel* ch;
        int bufferSize = kernelAudio::getRealBufSize() * 2;
 
        if (type == CHANNEL_SAMPLE)
@@ -150,7 +150,7 @@ Channel* addChannel(int type)
 
        while (true) {
                if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
-      continue;
+                       continue;
                mixer::channels.push_back(ch);
                pthread_mutex_unlock(&mixer::mutex_chans);
                break;
@@ -158,7 +158,7 @@ Channel* addChannel(int type)
 
        ch->index = getNewChanIndex();
        gu_log("[addChannel] channel index=%d added, type=%d, total=%d\n",
-    ch->index, ch->type, mixer::channels.size());
+               ch->index, ch->type, mixer::channels.size());
        return ch;
 }
 
@@ -182,7 +182,7 @@ int deleteChannel(Channel* ch)
 
        while (true) {
                if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
-      continue;
+                       continue;
                mixer::channels.erase(mixer::channels.begin() + index);
                delete ch;
                pthread_mutex_unlock(&mixer::mutex_chans);
@@ -194,7 +194,7 @@ int deleteChannel(Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-Channel *getChannelByIndex(int index)
+ChannelgetChannelByIndex(int index)
 {
        for (unsigned i=0; i<mixer::channels.size(); i++)
                if (mixer::channels.at(i)->index == index)
@@ -210,12 +210,12 @@ Channel *getChannelByIndex(int index)
 bool hasLogicalSamples()
 {
        for (unsigned i=0; i<mixer::channels.size(); i++) {
-    if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
-      continue;
-    SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
-    if (ch->wave && ch->wave->isLogical())
-      return true;
-  }
+               if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
+                       continue;
+               SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
+               if (ch->wave && ch->wave->isLogical())
+                       return true;
+       }
        return false;
 }
 
@@ -226,13 +226,13 @@ bool hasLogicalSamples()
 bool hasEditedSamples()
 {
        for (unsigned i=0; i<mixer::channels.size(); i++)
-  {
+       {
                if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
-      continue;
-    SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
-    if (ch->wave && ch->wave->isEdited())
-      return true;
-  }
+                       continue;
+               SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
+               if (ch->wave && ch->wave->isEdited())
+                       return true;
+       }
        return false;
 }
 
@@ -242,7 +242,7 @@ bool hasEditedSamples()
 
 void stopSequencer()
 {
-  clock::stop();
+       clock::stop();
        for (unsigned i=0; i<mixer::channels.size(); i++)
                mixer::channels.at(i)->stopBySeq(conf::chansStopOnSeqHalt);
 }
@@ -251,7 +251,7 @@ void stopSequencer()
 /* -------------------------------------------------------------------------- */
 
 
-bool uniqueSolo(Channel *ch)
+bool uniqueSolo(Channelch)
 {
        int solos = 0;
        for (unsigned i=0; i<mixer::channels.size(); i++) {
@@ -270,13 +270,13 @@ void readPatch()
 {
        mixer::ready = false;
 
-       mixer::outVol     = patch::masterVolOut;
-       mixer::inVol      = patch::masterVolIn;
+       mixer::outVol = patch::masterVolOut;
+       mixer::inVol = patch::masterVolIn;
        clock::setBpm(patch::bpm);
        clock::setBars(patch::bars);
        clock::setBeats(patch::beats);
        clock::setQuantize(patch::quantize);
-       mixer::metronome  = patch::metronome;
+       mixer::metronome = patch::metronome;
 
 #ifdef WITH_VST
 
@@ -373,12 +373,12 @@ void stopInputRec()
 
 bool hasArmedSampleChannels()
 {
-  for (unsigned i=0; i<mixer::channels.size(); i++) {
-    Channel *ch = mixer::channels.at(i);
-    if (ch->type == CHANNEL_SAMPLE && ch->armed)
-      return true;
-  }
-  return false;
+       for (unsigned i=0; i<mixer::channels.size(); i++) {
+               Channel *ch = mixer::channels.at(i);
+               if (ch->type == CHANNEL_SAMPLE && ch->armed)
+                       return true;
+       }
+       return false;
 }
 
 
index e0daf2e8cec8ff36a1ca3bc8fde655188ed3417a..495134df5289d2c4eff9def28d88021207e22950 100644 (file)
@@ -58,17 +58,18 @@ void sanitize()
   samplerate   = samplerate <= 0 ? G_DEFAULT_SAMPLERATE : samplerate;
 
   for (unsigned i=0; i<columns.size(); i++) {
-    column_t *col = &columns.at(i);
+    column_tcol = &columns.at(i);
     col->index = col->index < 0 ? 0 : col->index;
     col->width = col->width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col->width;
   }
 
   for (unsigned i=0; i<channels.size(); i++) {
-    channel_t *ch = &channels.at(i);
+    channel_t* ch = &channels.at(i);
+    ch->size   = ch->size < G_GUI_CHANNEL_H_1 || ch->size > G_GUI_CHANNEL_H_4 ? G_GUI_CHANNEL_H_1 : ch->size;
     ch->volume = ch->volume < 0.0f || ch->volume > 1.0f ? G_DEFAULT_VOL : ch->volume;
     ch->pan    = ch->pan < 0.0f || ch->pan > 1.0f ? 1.0f : ch->pan;
     ch->boost  = ch->boost < 1.0f ? G_DEFAULT_BOOST : ch->boost;
-    ch->pitch  = ch->pitch < 0.1f || ch->pitch > 4.0f ? G_DEFAULT_PITCH : ch->pitch;
+    ch->pitch  = ch->pitch < 0.1f || ch->pitch > G_MAX_PITCH ? G_DEFAULT_PITCH : ch->pitch;
   }
 }
 
@@ -78,7 +79,7 @@ void sanitize()
 /* setInvalid
 Helper function used to return invalid status while reading. */
 
-int setInvalid(json_t *jRoot)
+int setInvalid(json_tjRoot)
 {
   json_decref(jRoot);
   return PATCH_INVALID;
@@ -88,7 +89,7 @@ int setInvalid(json_t *jRoot)
 /* -------------------------------------------------------------------------- */
 
 
-bool readCommons(json_t *jContainer)
+bool readCommons(json_tjContainer)
 {
   if (!storager::setString(jContainer, PATCH_KEY_HEADER, header))  return 0;
   if (!storager::setString(jContainer, PATCH_KEY_VERSION, version)) return 0;
@@ -114,14 +115,14 @@ bool readCommons(json_t *jContainer)
 
 #ifdef WITH_VST
 
-bool readPlugins(json_t *jContainer, vector<plugin_t> *container, const char *key)
+bool readPlugins(json_t* jContainer, vector<plugin_t>* container, const char* key)
 {
-  json_t *jPlugins = json_object_get(jContainer, key);
+  json_tjPlugins = json_object_get(jContainer, key);
   if (!storager::checkArray(jPlugins, key))
     return 0;
 
   size_t pluginIndex;
-  json_t *jPlugin;
+  json_tjPlugin;
   json_array_foreach(jPlugins, pluginIndex, jPlugin) {
 
     if (!storager::checkObject(jPlugin, "")) // TODO pass pluginIndex as string
@@ -133,21 +134,21 @@ bool readPlugins(json_t *jContainer, vector<plugin_t> *container, const char *ke
 
     /* read plugin params */
 
-    json_t *jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
+    json_tjParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
     if (!storager::checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0;
 
     size_t paramIndex;
-    json_t *jParam;
+    json_tjParam;
     json_array_foreach(jParams, paramIndex, jParam)
       plugin.params.push_back(json_real_value(jParam));
 
     /* read midiIn params (midi learning on plugins' parameters) */
 
-    json_t *jMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
+    json_tjMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
     if (!storager::checkArray(jMidiInParams, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS)) return 0;
 
     size_t midiInParamIndex;
-    json_t *jMidiInParam;
+    json_tjMidiInParam;
     json_array_foreach(jMidiInParams, midiInParamIndex, jMidiInParam)
       plugin.midiInParams.push_back(json_integer_value(jMidiInParam));
 
@@ -161,14 +162,14 @@ bool readPlugins(json_t *jContainer, vector<plugin_t> *container, const char *ke
 /* -------------------------------------------------------------------------- */
 
 
-bool readActions(json_t *jContainer, channel_t *channel)
+bool readActions(json_t* jContainer, channel_t* channel)
 {
-  json_t *jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
+  json_tjActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
   if (!storager::checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS))
     return 0;
 
   size_t actionIndex;
-  json_t *jAction;
+  json_tjAction;
   json_array_foreach(jActions, actionIndex, jAction) {
 
     if (!storager::checkObject(jAction, "")) // TODO pass actionIndex as string
@@ -188,14 +189,14 @@ bool readActions(json_t *jContainer, channel_t *channel)
 /* -------------------------------------------------------------------------- */
 
 
-bool readChannels(json_t *jContainer)
+bool readChannels(json_tjContainer)
 {
-  json_t *jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
+  json_tjChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
   if (!storager::checkArray(jChannels, PATCH_KEY_CHANNELS))
     return 0;
 
   size_t channelIndex;
-  json_t *jChannel;
+  json_tjChannel;
   json_array_foreach(jChannels, channelIndex, jChannel) {
 
     string channelIndexStr = "channel " + gu_toString(channelIndex);
@@ -206,6 +207,7 @@ bool readChannels(json_t *jContainer)
 
     if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_TYPE,                 channel.type)) return 0;
     if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_INDEX,                channel.index)) return 0;
+    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_SIZE,                 channel.size)) return 0;
     if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_COLUMN,               channel.column)) return 0;
     if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE,                 channel.mute)) return 0;
     if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MUTE_S,               channel.mute_s)) return 0;
@@ -252,14 +254,14 @@ bool readChannels(json_t *jContainer)
 /* -------------------------------------------------------------------------- */
 
 
-bool readColumns(json_t *jContainer)
+bool readColumns(json_tjContainer)
 {
-  json_t *jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
+  json_tjColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
   if (!storager::checkArray(jColumns, PATCH_KEY_COLUMNS))
     return 0;
 
   size_t columnIndex;
-  json_t *jColumn;
+  json_tjColumn;
   json_array_foreach(jColumns, columnIndex, jColumn) {
 
     string columnIndexStr = "column " + gu_toString(columnIndex);
@@ -280,26 +282,26 @@ bool readColumns(json_t *jContainer)
 
 #ifdef WITH_VST
 
-void writePlugins(json_t *jContainer, vector<plugin_t> *plugins, const char *key)
+void writePlugins(json_t* jContainer, vector<plugin_t>* plugins, const char* key)
 {
-  json_t *jPlugins = json_array();
+  json_tjPlugins = json_array();
   for (unsigned j=0; j<plugins->size(); j++) {
-    json_t   *jPlugin = json_object();
-    plugin_t  plugin  = plugins->at(j);
+    json_t*  jPlugin = json_object();
+    plugin_t plugin  = plugins->at(j);
     json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH,   json_string(plugin.path.c_str()));
     json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass));
     json_array_append_new(jPlugins, jPlugin);
 
     /* plugin params */
 
-    json_t *jPluginParams = json_array();
+    json_tjPluginParams = json_array();
     for (unsigned z=0; z<plugin.params.size(); z++)
       json_array_append_new(jPluginParams, json_real(plugin.params.at(z)));
     json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PARAMS, jPluginParams);
 
     /* midiIn params (midi learning on plugins' parameters) */
 
-    json_t *jPluginMidiInParams = json_array();
+    json_tjPluginMidiInParams = json_array();
     for (unsigned z=0; z<plugin.midiInParams.size(); z++)
       json_array_append_new(jPluginMidiInParams, json_integer(plugin.midiInParams.at(z)));
     json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS, jPluginMidiInParams);
@@ -313,12 +315,12 @@ void writePlugins(json_t *jContainer, vector<plugin_t> *plugins, const char *key
 /* -------------------------------------------------------------------------- */
 
 
-void writeColumns(json_t *jContainer, vector<column_t> *columns)
+void writeColumns(json_t* jContainer, vector<column_t>* columns)
 {
-  json_t *jColumns = json_array();
+  json_tjColumns = json_array();
   for (unsigned i=0; i<columns->size(); i++) {
-    json_t   *jColumn = json_object();
-    column_t  column  = columns->at(i);
+    json_t*  jColumn = json_object();
+    column_t column  = columns->at(i);
     json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index));
     json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width));
     json_array_append_new(jColumns, jColumn);
@@ -330,12 +332,12 @@ void writeColumns(json_t *jContainer, vector<column_t> *columns)
 /* -------------------------------------------------------------------------- */
 
 
-void writeActions(json_t *jContainer, vector<action_t> *actions)
+void writeActions(json_t*jContainer, vector<action_t>*actions)
 {
-  json_t *jActions = json_array();
+  json_tjActions = json_array();
   for (unsigned k=0; k<actions->size(); k++) {
-    json_t   *jAction = json_object();
-    action_t  action  = actions->at(k);
+    json_t*  jAction = json_object();
+    action_t action  = actions->at(k);
     json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE,    json_integer(action.type));
     json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME,   json_integer(action.frame));
     json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue));
@@ -349,7 +351,7 @@ void writeActions(json_t *jContainer, vector<action_t> *actions)
 /* -------------------------------------------------------------------------- */
 
 
-void writeCommons(json_t *jContainer)
+void writeCommons(json_tjContainer)
 {
   json_object_set_new(jContainer, PATCH_KEY_HEADER,         json_string(header.c_str()));
   json_object_set_new(jContainer, PATCH_KEY_VERSION,        json_string(version.c_str()));
@@ -372,14 +374,15 @@ void writeCommons(json_t *jContainer)
 /* -------------------------------------------------------------------------- */
 
 
-void writeChannels(json_t *jContainer, vector<channel_t> *channels)
+void writeChannels(json_t* jContainer, vector<channel_t>* channels)
 {
-  json_t *jChannels = json_array();
+  json_tjChannels = json_array();
   for (unsigned i=0; i<channels->size(); i++) {
-    json_t    *jChannel = json_object();
-    channel_t  channel  = channels->at(i);
+    json_t*   jChannel = json_object();
+    channel_t channel  = channels->at(i);
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE,                 json_integer(channel.type));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX,                json_integer(channel.index));
+    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SIZE,                 json_integer(channel.size));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN,               json_integer(channel.column));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE,                 json_integer(channel.mute));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S,               json_integer(channel.mute_s));
@@ -477,9 +480,9 @@ void init()
 /* -------------------------------------------------------------------------- */
 
 
-int write(const string &file)
+int write(const stringfile)
 {
-  json_t *jRoot = json_object();
+  json_tjRoot = json_object();
 
   writeCommons(jRoot);
   writeColumns(jRoot, &columns);
@@ -490,7 +493,7 @@ int write(const string &file)
 #endif
 
   if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) {
-    gu_log("[write] unable to write patch file!\n");
+    gu_log("[patch::write] unable to write patch file!\n");
     return 0;
   }
   return 1;
@@ -500,12 +503,13 @@ int write(const string &file)
 /* -------------------------------------------------------------------------- */
 
 
-int read(const string &file)
+int read(const stringfile)
 {
   json_error_t jError;
-  json_t *jRoot = json_load_file(file.c_str(), 0, &jError);
+  json_tjRoot = json_load_file(file.c_str(), 0, &jError);
   if (!jRoot) {
-    gu_log("[read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text);
+    gu_log("[patch::read] unable to read patch file! Error on line %d: %s\n", 
+       jError.line, jError.text);
     return PATCH_UNREADABLE;
   }
 
index 2dd689da3fefc94ce84b9aa8c41e402ca677ff03..7018dbaeeca07c01ea1e212e1af75bb1abed2824 100644 (file)
@@ -44,72 +44,73 @@ namespace patch
 {
 struct action_t
 {
-  int      type;
-  int      frame;
-  float    fValue;
-  uint32_t iValue;
+       int      type;
+       int      frame;
+       float    fValue;
+       uint32_t iValue;
 };
 
 #ifdef WITH_VST
 struct plugin_t
 {
-  std::string           path;
-  bool                  bypass;
-  std::vector<float>    params;
-  std::vector<uint32_t> midiInParams;
+       std::string           path;
+       bool                  bypass;
+       std::vector<float>    params;
+       std::vector<uint32_t> midiInParams;
 };
 #endif
 
 struct channel_t
 {
-  int         type;
-  int         index;
-  int         column;
-  int         mute;
-  int         mute_s;
-  int         solo;
-  float       volume;
-  float       pan;
-  bool        midiIn;
-  uint32_t    midiInKeyPress;
-  uint32_t    midiInKeyRel;
-  uint32_t    midiInKill;
-  uint32_t    midiInArm;
-  uint32_t    midiInVolume;
-  uint32_t    midiInMute;
-  uint32_t    midiInSolo;
-  bool        midiOutL;
-  uint32_t    midiOutLplaying;
-  uint32_t    midiOutLmute;
-  uint32_t    midiOutLsolo;
-  // sample channel
-  std::string samplePath;
-  int         key;
-  int         mode;
-  int         begin;
-  int         end;
-  float       boost;
-  int         recActive;
-  float       pitch;
-  bool        inputMonitor;
-  uint32_t    midiInReadActions;
-  uint32_t    midiInPitch;
-  // midi channel
-  uint32_t    midiOut;
-  uint32_t    midiOutChan;
-
-  std::vector<action_t> actions;
+       int         type;
+       int         index;
+       int         size;
+       int         column;
+       int         mute;
+       int         mute_s;
+       int         solo;
+       float       volume;
+       float       pan;
+       bool        midiIn;
+       uint32_t    midiInKeyPress;
+       uint32_t    midiInKeyRel;
+       uint32_t    midiInKill;
+       uint32_t    midiInArm;
+       uint32_t    midiInVolume;
+       uint32_t    midiInMute;
+       uint32_t    midiInSolo;
+       bool        midiOutL;
+       uint32_t    midiOutLplaying;
+       uint32_t    midiOutLmute;
+       uint32_t    midiOutLsolo;
+       // sample channel
+       std::string samplePath;
+       int         key;
+       int         mode;
+       int         begin;
+       int         end;
+       float       boost;
+       int         recActive;
+       float       pitch;
+       bool        inputMonitor;
+       uint32_t    midiInReadActions;
+       uint32_t    midiInPitch;
+       // midi channel
+       uint32_t    midiOut;
+       uint32_t    midiOutChan;
+
+       std::vector<action_t> actions;
 
 #ifdef WITH_VST
-  std::vector<plugin_t> plugins;
+       std::vector<plugin_t> plugins;
 #endif
 };
 
 struct column_t
 {
-  int index;
-  int width;
-  std::vector<int> channels;
+       int index;
+       int width;
+       std::vector<int> channels;
 };
 
 extern std::string header;
@@ -144,8 +145,8 @@ void init();
 /* read/write
  * Read/write patch to/from file. */
 
-int write(const std::string &file);
-int read (const std::string &file);
+int write(const std::stringfile);
+int read (const std::stringfile);
 }}};  // giada::m::patch::
 
 #endif
index 04028184d7568dee0c36047dfd30c4b6c2542a32..83361f9fe8d24a89c3d6f61e46418d951d9de0b3 100644 (file)
 #ifdef WITH_VST
 
 
+#include <FL/Fl.H>
 #include "../utils/log.h"
+#include "../utils/time.h"
+#include "const.h"
 #include "plugin.h"
 
 
 using std::string;
+using namespace giada::u;
 
 
 int Plugin::idGenerator = 1;
@@ -48,21 +52,15 @@ Plugin::Plugin(juce::AudioPluginInstance *plugin, double samplerate,
     id    (idGenerator++),
     bypass(false)
 {
-  /* Fill midiInParams. All values are empty (0x0): they will be filled during
+  /* Init midiInParams. All values are empty (0x0): they will be filled during
   midi learning process. */
 
   for (int i=0; i<plugin->getNumParameters(); i++)
     midiInParams.push_back(0x0);
-
-  /* Try to enable editor (i.e. plugin's UI) */
   
-  ui = plugin->createEditorIfNeeded();
-  if (ui == nullptr)
-    gu_log("[Plugin] unable to create editor, the plugin might be GUI-less!\n");
-
   plugin->prepareToPlay(samplerate, buffersize);
 
-  gu_log("[Plugin] editor initialized and ready\n");
+  gu_log("[Plugin] plugin initialized and ready\n");
 }
 
 
@@ -71,6 +69,7 @@ Plugin::Plugin(juce::AudioPluginInstance *plugin, double samplerate,
 
 Plugin::~Plugin()
 {
+       closeEditor();
   plugin->suspendProcessing(true);
   plugin->releaseResources();
 }
@@ -79,12 +78,21 @@ Plugin::~Plugin()
 /* -------------------------------------------------------------------------- */
 
 
-void Plugin::showEditor(void *parent)
+void Plugin::showEditor(voidparent)
 {
+  ui = plugin->createEditorIfNeeded();
   if (ui == nullptr) {
-    gu_log("[Plugin::showEditor] can't show editor!\n");
+    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);
 }
@@ -95,7 +103,7 @@ void Plugin::showEditor(void *parent)
 
 bool Plugin::isEditorOpen()
 {
-  return ui->isVisible() && ui->isOnDesktop();
+  return ui != nullptr && ui->isVisible() && ui->isOnDesktop();
 }
 
 
@@ -250,8 +258,8 @@ void Plugin::closeEditor()
 {
   if (ui == nullptr)
     return;
-  if (ui->isOnDesktop())
-       ui->removeFromDesktop();
+  delete ui;
+  ui = nullptr;
 }
 
 #endif
index 312101534f6a9e0c90fa5905c85851d9d7d1bdd9..6ffdd805a2f4627b6d279123f22c3b77f46ba050 100644 (file)
@@ -305,7 +305,7 @@ void SampleChannel::setEnd(int f)
        if (f >= wave->getSize())
                end = (wave->getSize() - 1) * wave->getChannels();
        else
-       if (f <= begin)
+       if (f * wave->getChannels() <= begin)
                end = begin + wave->getChannels();
        else
                end = f * wave->getChannels();
@@ -823,6 +823,7 @@ void SampleChannel::reset(int frame)
        //fadeoutTracker = tracker;   // store old frame number for xfade
        tracker = begin;
        mute_i  = false;
+       qWait   = false;  // Was in qWait mode? Reset occured, no more qWait now.
        if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING))
                tracker = fillChan(vChan, tracker, frame);
 }
index 2f0e8ea62b4a5557a294f8d22d2869f7b1bf3950..a215a7c9d6e2523e0eb88d4f3f1d5dcf76fb68ef 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <cmath>
+#include <algorithm>
 #include "../utils/log.h"
 #include "wave.h"
 #include "waveFx.h"
@@ -43,25 +44,35 @@ void fadeFrame(Wave* w, int i, float val)
        for (int j=0; j<w->getChannels(); j++)
                frame[j] *= val;
 }
-}; // {anonymous}
 
 
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 
-float normalizeSoft(Wave *w)
+float getPeak(Wave* w, int a, int b)
 {
        float peak = 0.0f;
        float abs  = 0.0f;
-       for (int i=0; i<w->getSize(); i++) {
+       for (int i=a; i<b; i++) {
                float* frame = w->getFrame(i);
                for (int j=0; j<w->getChannels(); j++) // Find highest value in any channel
                        abs = fabs(frame[j]);
                if (abs > peak)
                        peak = abs;
        }
+       return peak;
+}
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+float normalizeSoft(Wave* w)
+{
+       float peak = getPeak(w, 0, w->getSize());
 
        /* peak == 0.0f: don't normalize the silence
         * peak > 1.0f: don't reduce the amplitude, just leave it alone */
@@ -76,6 +87,24 @@ float normalizeSoft(Wave *w)
 /* -------------------------------------------------------------------------- */
 
 
+void normalizeHard(Wave* w, int a, int b)
+{
+       float peak = getPeak(w, a, b);
+       if (peak == 0.0f || peak > 1.0f)  // as in ::normalizeSoft
+               return;
+
+       for (int i=a; i<b; i++) {
+               float* frame = w->getFrame(i);
+               for (int j=0; j<w->getChannels(); j++)
+                       frame[j] = frame[j] * (1.0f / peak);
+       }
+       w->setEdited(true);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 int monoToStereo(Wave* w)
 {
        if (w->getChannels() >= G_DEFAULT_AUDIO_CHANS)
@@ -117,8 +146,6 @@ void silence(Wave* w, int a, int b)
        }
 
        w->setEdited(true);
-
-       return;
 }
 
 
@@ -170,7 +197,7 @@ int trim(Wave* w, int a, int b)
        int newSize = (b - a) * w->getChannels();
        float* newData = new (std::nothrow) float[newSize];
        if (newData == nullptr) {
-               gu_log("[wfx] unable to allocate memory for trimming\n");
+               gu_log("[wfx::trim] unable to allocate memory!\n");
                return G_RES_ERR_MEMORY;
        }
 
@@ -193,6 +220,47 @@ int trim(Wave* w, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
+int paste(Wave* src, Wave* des, int aFrame)
+{
+       int srcNumSamples = src->getSize() * src->getChannels();
+       int desNumSamples = des->getSize() * des->getChannels();
+       int aSample = aFrame * des->getChannels();
+
+       int newSize = srcNumSamples + desNumSamples;
+       float* newData = new (std::nothrow) float[newSize];
+       if (newData == nullptr) {
+               gu_log("[wfx::paste] unable to allocate memory!\n");
+               return G_RES_ERR_MEMORY;
+       }
+
+       /* |---original data---|///paste data///|---original data---|
+                 chunk 1            chunk 2          chunk 3
+       */
+
+       float* chunk1a = des->getData();
+       float* chunk1b = des->getData() + aSample;
+
+       float* chunk2a = src->getData();
+       float* chunk2b = src->getData() + srcNumSamples;        
+
+       float* chunk3a = chunk1b;
+       float* chunk3b = des->getData() + desNumSamples;
+
+       std::copy(chunk1a, chunk1b, newData);
+       std::copy(chunk2a, chunk2b, newData + aSample); 
+       std::copy(chunk3a, chunk3b, newData + aSample + srcNumSamples);
+
+       des->free();
+       des->setData(newData, newSize);
+       des->setEdited(true);
+
+       return G_RES_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void fade(Wave* w, int a, int b, int type)
 {
        gu_log("[wfx::fade] fade from %d to %d (range = %d)\n", a, b, b-a);
@@ -230,4 +298,20 @@ void smooth(Wave* w, int a, int b)
        w->setEdited(true);
 }
 
+
+/* -------------------------------------------------------------------------- */
+
+
+void reverse(Wave* w, int a, int b)
+{
+       /* https://stackoverflow.com/questions/33201528/reversing-an-array-of-structures-in-c */
+
+       float* begin = (w->getData() + (a * w->getChannels()));
+       float* end   = (w->getData() + (b * w->getChannels()));
+
+       std::reverse(begin, end);
+
+       w->setEdited(true);
+}
+
 }}}; // giada::m::wfx::
\ No newline at end of file
index 43600528521b60111c1c013334f68f3637cf4a60..438c7b6e1a8ed20181ef9c690d30291797faf2fe 100644 (file)
@@ -45,20 +45,32 @@ Normalizes the wave by returning the dB value for the boost volume. */
 
 float normalizeSoft(Wave* w);
 
+/* normalizeHard
+Normalizes the wave in range a-b by altering values in memory. */
+
+void normalizeHard(Wave* w, int a, int b);
+
 int monoToStereo(Wave* w);
 void silence(Wave* w, int a, int b);
 int cut(Wave* w, int a, int b);
 int trim(Wave* w, int a, int b);
+int paste(Wave* src, Wave* dest, int a);
 
 /* fade
- * fade in or fade out selection. Fade In = type 0, Fade Out = type 1 */
+Fades in or fades out selection. Fade In = type 0, Fade Out = type 1 */
 
 void fade(Wave* w, int a, int b, int type);
 
 /* smooth
- * smooth edges of selection. */
+Smooth edges of selection. */
 
 void smooth(Wave* w, int a, int b);
+
+/* reverse
+Flips Wave's data. */
+
+void reverse(Wave* w, int a, int b);
+
 }}}; // giada::m::wfx::
 
 #endif
index bd102b4996bde162b405bd30180d53873873eba5..3e430e45605591671b3b4ffa921914e1ef452787 100644 (file)
@@ -50,13 +50,13 @@ int getBits(SF_INFO& header)
        if      (header.format & SF_FORMAT_PCM_S8)
                return 8;
        else if (header.format & SF_FORMAT_PCM_16)
-               return 16;      
+               return 16;
        else if (header.format & SF_FORMAT_PCM_24)
-               return 24;      
+               return 24;
        else if (header.format & SF_FORMAT_PCM_32)
-               return 32;      
+               return 32;
        else if (header.format & SF_FORMAT_PCM_U8)
-               return 8;       
+               return 8;
        else if (header.format & SF_FORMAT_FLOAT)
                return 32;
        else if (header.format & SF_FORMAT_DOUBLE)
@@ -99,7 +99,7 @@ int create(const string& path, Wave** out)
        frame1 = [leftChannel, rightChannel]
        frame2 = [leftChannel, rightChannel]
        ... */
-       
+
        int size = header.frames * header.channels;
        float* data = new (std::nothrow) float[size];
        if (data == nullptr) {
@@ -112,7 +112,7 @@ int create(const string& path, Wave** out)
 
        sf_close(fileIn);
 
-       Wave* wave = new Wave(data, size, header.channels, header.samplerate, 
+       Wave* wave = new Wave(data, size, header.channels, header.samplerate,
                getBits(header), path);
 
        if (header.channels == 1 && !wfx::monoToStereo(wave)) {
@@ -139,8 +139,9 @@ int createEmpty(int size, int samplerate, const string& name, Wave** out)
                return G_RES_ERR_MEMORY;
        }
 
-       Wave *wave = new Wave(data, size, 2, samplerate, G_DEFAULT_BIT_DEPTH, "");
-       wave->setLogical(true); 
+       Wave* wave = new Wave(data, size, G_DEFAULT_AUDIO_CHANS, samplerate, 
+               G_DEFAULT_BIT_DEPTH, "");
+       wave->setLogical(true);
        wave->setName(name);
        wave->setPath(gu_getCurrentPath() + G_SLASH + wave->getName());
 
@@ -155,6 +156,34 @@ int createEmpty(int size, int samplerate, const string& name, Wave** out)
 /* -------------------------------------------------------------------------- */
 
 
+int createFromWave(const Wave* src, int a, int b, Wave** out)
+{
+       int numChans = src->getChannels();
+       int size = (b - a) * numChans;
+       float* data = new (std::nothrow) float[size];
+       if (data == nullptr) {
+               gu_log("[waveManager::createFromWave] unable to allocate memory\n");
+               return G_RES_ERR_MEMORY;
+       }
+
+       std::copy(src->getData() + (a*numChans), src->getData() + (b*numChans), data);
+
+       Wave* wave = new Wave(data, size, numChans, src->getRate(),
+               src->getBits(), src->getPath());
+       wave->setLogical(true);
+       wave->setName(src->getName() + " part");
+
+       *out = wave;
+
+       gu_log("[waveManager::createFromWave] new Wave created, %d frames\n", size);
+
+       return G_RES_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 int resample(Wave* w, int quality, int samplerate)
 {
        float ratio = samplerate / (float) w->getRate();
@@ -174,7 +203,7 @@ int resample(Wave* w, int quality, int samplerate)
        src_data.output_frames = newSizeFrames;
        src_data.src_ratio     = ratio;
 
-       gu_log("[waveManager::resample] resampling: new size=%d (%d frames)\n", 
+       gu_log("[waveManager::resample] resampling: new size=%d (%d frames)\n",
                newSizeSamples, newSizeFrames);
 
        int ret = src_simple(&src_data, quality, w->getChannels());
@@ -204,7 +233,7 @@ int save(Wave* w, const string& path)
 
        SNDFILE* file = sf_open(path.c_str(), SFM_WRITE, &header);
        if (file == nullptr) {
-               gu_log("[waveManager::save] unable to open %s for exporting: %s\n", 
+               gu_log("[waveManager::save] unable to open %s for exporting: %s\n",
                        path.c_str(), sf_strerror(file));
                return G_RES_ERR_IO;
        }
@@ -216,7 +245,7 @@ int save(Wave* w, const string& path)
 
        w->setLogical(false);
        w->setEdited(false);
-       
+
        return G_RES_OK;
 }
 }}}; // giada::m::waveManager
index b9e8a059f52fa2d767c503eb131ec82abb852c50..2772b5916001cebc82d009b15a0523874af8da49 100644 (file)
@@ -49,6 +49,12 @@ Creates a new silent Wave object. Note: 'size' must take 2 channels into account
 (stereo). */
 
 int createEmpty(int size, int samplerate, const std::string& name, Wave** out);
+
+/* createFromWave
+Creates a new Wave from an existing one, copying the data in range a - b. */
+
+int createFromWave(const Wave* src, int a, int b, Wave** out);
+
 int resample(Wave* w, int quality, int samplerate); 
 int save(Wave* w, const std::string& path);
 
index d9c13d5f1304f570bd510c98b0b57ea7f6912f6d..12f7582bff5c8169fc890c5be40d5361a985512f 100644 (file)
@@ -74,13 +74,14 @@ static bool __soloSession__ = false;
 
 int glue_loadChannel(SampleChannel* ch, const string& fname)
 {
-  /* Always stop a channel before loading a new sample in it. This will prevent
-  issues if tracker is outside the boundaries of the new sample -> segfault. */
+       /* Always stop a channel before loading a new sample in it. This will prevent
+       issues if tracker is outside the boundaries of the new sample -> segfault. */
 
-  ch->hardStop(0);
+       if (ch->status & (STATUS_PLAY | STATUS_ENDING))
+               ch->hardStop(0);
 
-       /* save the patch and take the last browser's dir in order to re-use it
-        * the next time */
+       /* Save the patch and take the last browser's dir in order to re-use it the 
+       next time. */
 
        conf::samplePath = gu_dirname(fname);
 
@@ -110,10 +111,10 @@ int glue_loadChannel(SampleChannel* ch, const string& fname)
 /* -------------------------------------------------------------------------- */
 
 
-Channel* glue_addChannel(int column, int type)
+Channel* glue_addChannel(int column, int type, int size)
 {
        Channel* ch     = mh::addChannel(type);
-       geChannel* gch  = G_MainWin->keyboard->addChannel(column, ch);
+       geChannel* gch  = G_MainWin->keyboard->addChannel(column, ch, size);
        ch->guiChannel  = gch;
        return ch;
 }
@@ -124,10 +125,10 @@ Channel* glue_addChannel(int column, int type)
 
 void glue_deleteChannel(Channel* ch)
 {
-  if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
-    return;
-  recorder::clearChan(ch->index);
-  ch->hasActions = false;
+       if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+               return;
+       recorder::clearChan(ch->index);
+       ch->hasActions = false;
 #ifdef WITH_VST
        pluginHost::freeStack(pluginHost::CHANNEL, &mixer::mutex_plugins, ch);
 #endif
@@ -144,25 +145,25 @@ void glue_deleteChannel(Channel* ch)
 
 void glue_freeChannel(Channel *ch)
 {
-  if (ch->status == STATUS_PLAY) {
-    if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
-      return;
-  }
-  else
-  if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
-    return;
+       if (ch->status == STATUS_PLAY) {
+               if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
+                       return;
+       }
+       else
+       if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
+               return;
 
        G_MainWin->keyboard->freeChannel(ch->guiChannel);
        recorder::clearChan(ch->index);
-  ch->hasActions = false;
+       ch->hasActions = false;
        ch->empty();
 
-  /* delete any related subwindow */
-  /** TODO - use gu_closeAllSubwindows()   */
-  G_MainWin->delSubWindow(WID_FILE_BROWSER);
-  G_MainWin->delSubWindow(WID_ACTION_EDITOR);
-  G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
-  G_MainWin->delSubWindow(WID_FX_LIST);
+       /* delete any related subwindow */
+       /** TODO - use gu_closeAllSubwindows()   */
+       G_MainWin->delSubWindow(WID_FILE_BROWSER);
+       G_MainWin->delSubWindow(WID_ACTION_EDITOR);
+       G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
+       G_MainWin->delSubWindow(WID_FX_LIST);
 }
 
 
@@ -182,8 +183,8 @@ void glue_toggleArm(Channel *ch, bool gui)
 
 void glue_toggleInputMonitor(Channel *ch)
 {
-  SampleChannel *sch = static_cast<SampleChannel*>(ch);
-  sch->inputMonitor = !sch->inputMonitor;
+       SampleChannel *sch = static_cast<SampleChannel*>(ch);
+       sch->inputMonitor = !sch->inputMonitor;
 }
 
 
@@ -193,7 +194,8 @@ void glue_toggleInputMonitor(Channel *ch)
 int glue_cloneChannel(Channel *src)
 {
        Channel *ch    = mh::addChannel(src->type);
-       geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch);
+       geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), 
+               ch, src->guiChannel->getSize());
 
        ch->guiChannel = gch;
        ch->copy(src, &mixer::mutex_plugins);
@@ -212,14 +214,14 @@ void glue_setVolume(Channel *ch, float v, bool gui, bool editor)
 
        /* Changing channel volume? Update wave editor (if it's shown). */
 
-  if (!editor) {
-       gdSampleEditor *gdEditor = (gdSampleEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR);
-       if (gdEditor) {
-               Fl::lock();
-               gdEditor->volumeTool->refresh();
-               Fl::unlock();
-       }
-  }
+       if (!editor) {
+               gdSampleEditor *gdEditor = (gdSampleEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR);
+               if (gdEditor) {
+                       Fl::lock();
+                       gdEditor->volumeTool->refresh();
+                       Fl::unlock();
+               }
+       }
 
        if (!gui) {
                Fl::lock();
@@ -232,10 +234,10 @@ void glue_setVolume(Channel *ch, float v, bool gui, bool editor)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_setPitch(SampleChannel *ch, float val)
+void glue_setPitch(SampleChannelch, float val)
 {
        ch->setPitch(val);
-       gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+       gdSampleEditorgdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
        if (gdEditor) {
                Fl::lock();
                gdEditor->pitchTool->refresh();
@@ -247,10 +249,10 @@ void glue_setPitch(SampleChannel *ch, float val)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_setPanning(SampleChannel *ch, float val)
+void glue_setPanning(SampleChannelch, float val)
 {
        ch->setPan(val);
-       gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+       gdSampleEditorgdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
        if (gdEditor) {
                Fl::lock();
                gdEditor->panTool->refresh();
@@ -267,12 +269,12 @@ void glue_setMute(Channel *ch, bool gui)
        if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording)) {
                if (!ch->mute) {
                        recorder::startOverdub(ch->index, G_ACTION_MUTES, clock::getCurrentFrame(),
-        kernelAudio::getRealBufSize());
-      ch->readActions = false;   // don't read actions while overdubbing
-    }
+                               kernelAudio::getRealBufSize());
+                       ch->readActions = false;   // don't read actions while overdubbing
+               }
                else
                 recorder::stopOverdub(clock::getCurrentFrame(), clock::getTotalFrames(),
-      &mixer::mutex_recs);
+                       &mixer::mutex_recs);
        }
 
        ch->mute ? ch->unsetMute(false) : ch->setMute(false);
index b3ac92948da251eb33b021570a15811228bdf41b..65cd77e8998079150e994f5e1ba5660abe9b285c 100644 (file)
@@ -40,7 +40,7 @@ class gdSampleEditor;
 /* addChannel
  * add an empty new channel to the stack. Returns the new channel. */
 
-Channel *glue_addChannel(int column, int type);
+Channel *glue_addChannel(int column, int type, int size);
 
 /* loadChannel
  * fill an existing channel with a wave. */
index efc8c67731a85215db932c9416187f0d1addd437..206726100d6310336ba92e695aa966672bc11359 100644 (file)
@@ -56,10 +56,10 @@ using namespace giada::m;
 
 void glue_setBpm(const char *v1, const char *v2)
 {
-  /* Never change this stuff while recording audio */
+       /* Never change this stuff while recording audio */
 
-  if (mixer::recording)
-    return;
+       if (mixer::recording)
+               return;
 
        char  bpmS[6];
        float bpmF = atof(v1) + (atof(v2)/10);
@@ -76,14 +76,15 @@ void glue_setBpm(const char *v1, const char *v2)
 
        float oldBpmF = clock::getBpm();
        clock::setBpm(bpmF);
-  recorder::updateBpm(oldBpmF, bpmF, clock::getQuanto());
+       recorder::updateBpm(oldBpmF, bpmF, clock::getQuanto());
+       mixer::allocVirtualInput(clock::getTotalFrames());
 
 #ifdef __linux__
-  kernelAudio::jackSetBpm(clock::getBpm());
+       kernelAudio::jackSetBpm(clock::getBpm());
 #endif
 
-  gu_refreshActionEditor();
-  G_MainWin->mainTimer->setBpm(bpmS);
+       gu_refreshActionEditor();
+       G_MainWin->mainTimer->setBpm(bpmS);
 
        gu_log("[glue] Bpm changed to %s (real=%f)\n", bpmS, clock::getBpm());
 }
@@ -94,13 +95,13 @@ void glue_setBpm(const char *v1, const char *v2)
 
 void glue_setBpm(float v)
 {
-  if (v < G_MIN_BPM || v > G_MAX_BPM)
-    v = G_DEFAULT_BPM;
-  double fIpart;
-  double fPpart = modf(v, &fIpart);
-  int iIpart = fIpart;
-  int iPpart = ceilf(fPpart);
-  glue_setBpm(gu_toString(iIpart).c_str(), gu_toString(iPpart).c_str());
+       if (v < G_MIN_BPM || v > G_MAX_BPM)
+               v = G_DEFAULT_BPM;
+       double fIpart;
+       double fPpart = modf(v, &fIpart);
+       int iIpart = fIpart;
+       int iPpart = ceilf(fPpart);
+       glue_setBpm(gu_toString(iIpart).c_str(), gu_toString(iPpart).c_str());
 }
 
 
@@ -109,10 +110,10 @@ void glue_setBpm(float v)
 
 void glue_setBeats(int beats, int bars, bool expand)
 {
-  /* Never change this stuff while recording audio */
+       /* Never change this stuff while recording audio */
 
-  if (mixer::recording)
-    return;
+       if (mixer::recording)
+               return;
 
        /* Temp vars to store old data (they are necessary) */
 
@@ -125,7 +126,7 @@ void glue_setBeats(int beats, int bars, bool expand)
        mixer::allocVirtualInput(clock::getTotalFrames());
 
        /* Update recorded actions, if 'expand' required and an expansion is taking
-  place. */
+       place. */
 
        if (expand && clock::getBeats() > oldBeats)
                recorder::expand(oldTotalFrames, clock::getTotalFrames());
@@ -142,13 +143,13 @@ void glue_rewindSeq(bool gui, bool notifyJack)
 {
        mh::rewindSequencer();
 
-  /* FIXME - potential desync when Quantizer is enabled from this point on.
-  Mixer would wait, while the following calls would be made regardless of its
-  state. */
+       /* FIXME - potential desync when Quantizer is enabled from this point on.
+       Mixer would wait, while the following calls would be made regardless of its
+       state. */
 
 #ifdef __linux__
-  if (notifyJack)
-         kernelAudio::jackSetPosition(0);
+       if (notifyJack)
+               kernelAudio::jackSetPosition(0);
 #endif
 
        if (conf::midiSync == MIDI_SYNC_CLOCK_M)
@@ -236,7 +237,7 @@ void glue_resetToInitState(bool resetGui, bool createColumns)
        if (createColumns)
                G_MainWin->keyboard->init();
 
-  gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
+       gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
 
        if (resetGui)
                gu_updateControls();
index ecaade6fd1ae710d496d91fbe30d9f20a1fb26ba..0c20347f301eb001f62f43eb2f4318b4324354ed 100644 (file)
 #include "../gui/elems/sampleEditor/pitchTool.h"
 #include "../gui/elems/sampleEditor/rangeTool.h"
 #include "../gui/elems/sampleEditor/waveform.h"
+#include "../gui/elems/mainWindow/keyboard/channel.h"
 #include "../core/sampleChannel.h"
 #include "../core/waveFx.h"
+#include "../core/wave.h"
+#include "../core/waveManager.h"
 #include "../core/const.h"
 #include "../utils/gui.h"
+#include "../utils/log.h"
 #include "channel.h"
 #include "sampleEditor.h"
 
@@ -56,6 +60,18 @@ namespace giada {
 namespace c     {
 namespace sampleEditor
 {
+namespace
+{
+       /* m_waveBuffer
+       A Wave used during cut/copy/paste operations. */
+
+       Wave* m_waveBuffer = nullptr;
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 gdSampleEditor* getSampleEditorWindow()
 {
        gdSampleEditor* se = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
@@ -67,7 +83,7 @@ gdSampleEditor* getSampleEditorWindow()
 /* -------------------------------------------------------------------------- */
 
 
-void setBeginEndChannel(SampleChannel* ch, int b, int e)
+void setBeginEnd(SampleChannel* ch, int b, int e)
 {
        ch->setBegin(b);
        ch->setEnd(e);
@@ -75,6 +91,10 @@ void setBeginEndChannel(SampleChannel* ch, int b, int e)
        Fl::lock();
        gdEditor->rangeTool->refresh();
        Fl::unlock();
+
+       gdEditor->waveTools->waveform->recalcPoints();
+       gdEditor->waveTools->waveform->clearSel();
+       gdEditor->waveTools->waveform->redraw();
 }
 
 
@@ -87,7 +107,7 @@ void cut(SampleChannel* ch, int a, int b)
                gdAlert("Unable to cut the sample!");
                return;
        }
-       setBeginEndChannel(ch, ch->getBegin(), ch->getEnd());
+       setBeginEnd(ch, ch->getBegin(), ch->getEnd());
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->clearSel();
        gdEditor->waveTools->waveform->refresh();
@@ -98,6 +118,47 @@ void cut(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
+void copy(SampleChannel* ch, int a, int b)
+{
+       if (m_waveBuffer != nullptr)
+               delete m_waveBuffer;
+
+       int result = waveManager::createFromWave(ch->wave, a, b, &m_waveBuffer);
+       if (result != G_RES_OK) {
+               gu_log("[sampleEditor::copy] unable to create wave buffer!\n");
+               return;
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void paste(SampleChannel* ch, int a)
+{
+       if (!isWaveBufferFull())
+               return;
+       
+       wfx::paste(m_waveBuffer, ch->wave, a);
+
+       /* Shift begin/end points to keep the previous position. */
+
+       int delta = m_waveBuffer->getSize();
+       if (a < ch->getBegin() && a < ch->getEnd())
+               setBeginEnd(ch, ch->getBegin() + delta, ch->getEnd() + delta);
+       else
+       if (a < ch->getEnd())
+               setBeginEnd(ch, ch->getBegin(), ch->getEnd() + delta);
+
+       gdSampleEditor* gdEditor = getSampleEditorWindow();
+       gdEditor->waveTools->waveform->clearSel();
+       gdEditor->waveTools->waveform->refresh();
+       gdEditor->updateInfo();
+}
+
+/* -------------------------------------------------------------------------- */
+
+
 void silence(SampleChannel* ch, int a, int b)
 {
        wfx::silence(ch->wave, a, b);
@@ -131,13 +192,22 @@ void smoothEdges(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void setStartEnd(SampleChannel* ch, int a, int b)
+void reverse(SampleChannel* ch, int a, int b)
 {
-       setBeginEndChannel(ch, a, b);
+       wfx::reverse(ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
-       gdEditor->waveTools->waveform->recalcPoints();
-       gdEditor->waveTools->waveform->clearSel();
-       gdEditor->waveTools->waveform->redraw();
+       gdEditor->waveTools->waveform->refresh();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void normalizeHard(SampleChannel* ch, int a, int b)
+{
+       wfx::normalizeHard(ch->wave, a, b);
+       gdSampleEditor* gdEditor = getSampleEditorWindow();
+       gdEditor->waveTools->waveform->refresh();
 }
 
 
@@ -150,7 +220,7 @@ void trim(SampleChannel* ch, int a, int b)
                gdAlert("Unable to trim the sample!");
                return;
        }
-       setBeginEndChannel(ch, ch->getBegin(), ch->getEnd());
+       setBeginEnd(ch, ch->getBegin(), ch->getEnd());
        gdSampleEditor* gdEditor = getSampleEditorWindow();
        gdEditor->waveTools->waveform->clearSel();
        gdEditor->waveTools->waveform->refresh();
@@ -191,4 +261,35 @@ void rewindPreview(SampleChannel* ch)
        else
                setPlayHead(ch, 0);
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void toNewChannel(SampleChannel* ch, int a, int b)
+{
+       SampleChannel* newCh = static_cast<SampleChannel*>(glue_addChannel(
+               ch->guiChannel->getColumnIndex(), CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+
+       Wave* wave = nullptr;
+       int result = waveManager::createFromWave(ch->wave, a, b, &wave);
+       if (result != G_RES_OK) {
+               gdAlert("Unable to copy to new channel!");
+               return;
+       }
+
+       newCh->pushWave(wave, true);
+
+       newCh->guiChannel->update();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool isWaveBufferFull()
+{
+       return m_waveBuffer != nullptr;
+}
+
 }}}; // giada::c::sampleEditor::
index e4feeec2736d4aa3d6c90e383f4f871e9325ad71..3846f9ff83b16d48f8d2676b3a09ad9c6b1e25e5 100644 (file)
@@ -39,17 +39,28 @@ namespace sampleEditor
 {
 
 
-/* setBeginEndChannel
+/* setBeginEnd
 Sets start/end points in the sample editor. */
 
-void setBeginEndChannel(SampleChannel* ch, int b, int e);
+void setBeginEnd(SampleChannel* ch, int b, int e);
 
 void cut(SampleChannel* ch, int a, int b);
+void copy(SampleChannel* ch, int a, int b);
+
+/* paste
+Pastes what's defined in m_copyBuffer into channel 'ch' at point 'a'. If 
+m_copyBuffer is empty, does nothing. */
+
+void paste(SampleChannel* ch, int a);
+
 void trim(SampleChannel* ch, int a, int b);
+void reverse(SampleChannel* ch, int a, int b);
+void normalizeHard(SampleChannel* ch, int a, int b);
 void silence(SampleChannel* ch, int a, int b);
 void fade(SampleChannel* ch, int a, int b, int type);
 void smoothEdges(SampleChannel* ch, int a, int b);
-void setStartEnd(SampleChannel* ch, int a, int b);
+
+bool isWaveBufferFull();
 
 /* setPlayHead
 Changes playhead's position. Used in preview. */
@@ -58,6 +69,11 @@ void setPlayHead(SampleChannel* ch, int f);
 
 void setPreview(SampleChannel* ch, int mode);
 void rewindPreview(SampleChannel* ch);
+
+/* toNewChannel
+Copies the selected range into a new sample channel. */
+
+void toNewChannel(SampleChannel* ch, int a, int b);
 }}}; // giada::c::sampleEditor::
 
 #endif
index c853a9b59866487c7fe8fe08d30bd89943a0cc3e..da1a80fee1708044cf255774d22207286c350e43 100644 (file)
@@ -129,8 +129,8 @@ static void __glue_fillPatchGlobals__(const string &name)
        patch::beats        = clock::getBeats();
        patch::quantize     = clock::getQuantize();
        patch::masterVolIn  = mixer::inVol;
-  patch::masterVolOut = mixer::outVol;
-  patch::metronome    = mixer::metronome;
+       patch::masterVolOut = mixer::outVol;
+       patch::metronome    = mixer::metronome;
 
 #ifdef WITH_VST
 
@@ -194,9 +194,9 @@ void glue_savePatch(void *data)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_loadPatch(void *data)
+void glue_loadPatch(voiddata)
 {
-       gdBrowserLoad *browser = (gdBrowserLoad*) data;
+       gdBrowserLoadbrowser = (gdBrowserLoad*) data;
        string fullPath        = browser->getSelectedItem();
        bool isProject         = gu_isProject(browser->getSelectedItem());
 
@@ -239,15 +239,15 @@ void glue_loadPatch(void *data)
         * by 0.8 / total_channels steps.  */
 
        float steps = 0.8 / patch::channels.size();
-       for (unsigned i=0; i<patch::columns.size(); i++) {
-               patch::column_t *col = &patch::columns.at(i);
-               G_MainWin->keyboard->addColumn(col->width);
+       
+       for (const patch::column_t& col : patch::columns) {
+               G_MainWin->keyboard->addColumn(col.width);
                for (unsigned k=0; k<patch::channels.size(); k++) {
-                       if (patch::channels.at(k).column == col->index) {
-                               Channel *ch = glue_addChannel(patch::channels.at(k).column,
-                                       patch::channels.at(k).type);
+                       if (patch::channels.at(k).column == col.index) {
+                               Channelch = glue_addChannel(patch::channels.at(k).column,
+                                       patch::channels.at(k).type, patch::channels.at(k).size);
                                ch->readPatch(basePath, k, &mixer::mutex_plugins, conf::samplerate,
-          conf::rsmpQuality);
+                                       conf::rsmpQuality);
                        }
                        browser->setStatusBar(steps);
                }
@@ -348,15 +348,16 @@ void glue_saveProject(void *data)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_loadSample(void *data)
+void glue_loadSample(voiddata)
 {
-       gdBrowserLoad *browser = (gdBrowserLoad*) data;
+       gdBrowserLoadbrowser = (gdBrowserLoad*) data;
        string fullPath        = browser->getSelectedItem();
 
        if (fullPath.empty())
                return;
 
-       int res = glue_loadChannel((SampleChannel*) browser->getChannel(), fullPath.c_str());
+       int res = glue_loadChannel(static_cast<SampleChannel*>(browser->getChannel()), 
+               fullPath);
 
        if (res == G_RES_OK) {
                conf::samplePath = gu_dirname(fullPath);
@@ -391,7 +392,7 @@ void glue_saveSample(void *data)
                        return;
 
        if (static_cast<SampleChannel*>(browser->getChannel())->save(filePath.c_str())) {
-    gu_log("[glue_saveSample] sample saved to %s\n", filePath.c_str());
+               gu_log("[glue_saveSample] sample saved to %s\n", filePath.c_str());
                conf::samplePath = gu_dirname(filePath);
                browser->do_callback();
        }
index 6dba08e50daff3d83b44d79b0effe4e9425dfc8b..723763ff605ad3193d8743f801a62a2ba52a07cc 100644 (file)
@@ -124,7 +124,8 @@ gdActionEditor::gdActionEditor(Channel *chan)
        else {
                pr = new geNoteEditor(scroller->x(), upperArea->y()+upperArea->h()+8, this);
                scroller->add(pr);
-               scroller->add(new geResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8));
+               /* TODO - avoid magic number 30 for minimum height */
+               scroller->add(new geResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 30, 8));
        }
 
        end();
index 2ee9b81573a082b10f98c5338cf729c25b08fb80..efe3e0e95f4616c9158c9842c96a84031263890d 100644 (file)
@@ -76,7 +76,7 @@ public:
        inline void __cb_zoomIn();
        inline void __cb_zoomOut();
 
-       geChoice    *actionType;
+       geChoice   *actionType;
        geGridTool *gridTool;
        geButton   *zoomIn;
        geButton   *zoomOut;
index 0d8b47441b3b04c173b2aa678b8912ecbfd678cf..6c250f6fcb1c77296ec19691fdedec286004a570 100644 (file)
@@ -83,7 +83,7 @@ gdSampleEditor::gdSampleEditor(SampleChannel* ch)
 
   gu_setFavicon(this);
   set_non_modal();
-  label(ch->wave->getName().c_str());
+  copy_label(ch->wave->getName().c_str());
 
   size_range(720, 480);
   if (conf::sampleEditorX)
@@ -290,6 +290,7 @@ void gdSampleEditor::__cb_rewindPreview()
 
 void gdSampleEditor::__cb_reload()
 {
+  /* TODO - move to glue::sampleEditor */
   if (!gdConfirmWin("Warning", "Reload sample: are you sure?"))
     return;
 
@@ -306,7 +307,7 @@ void gdSampleEditor::__cb_reload()
   waveTools->waveform->stretchToWindow();
   waveTools->updateWaveform();
 
-  sampleEditor::setBeginEndChannel(ch, 0, ch->wave->getSize());
+  sampleEditor::setBeginEnd(ch, 0, ch->wave->getSize());
 
   redraw();
 }
index 36746b218a8a6b3b7c2e2adeb3b1e3ac93500bb7..90b4a100ff81c16fe0b1d84770d2589d5a0b4de7 100644 (file)
@@ -163,45 +163,45 @@ void gePianoRoll::drawSurface1()
                switch (i % KEYS) {
                        case (int) Notes::G:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%dG", octave);
+                               sprintf(note, "%d G", octave);
                                break;
                        case (int) Notes::FS:
-                               sprintf(note, "%dF#", octave);
+                               sprintf(note, "%d F#", octave);
                                break;
                        case (int) Notes::F:
-                               sprintf(note, "%dF", octave);
+                               sprintf(note, "%d F", octave);
                                break;
                        case (int) Notes::E:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%dE", octave);
+                               sprintf(note, "%d E", octave);
                                break;
                        case (int) Notes::DS:
-                               sprintf(note, "%dD#", octave);
+                               sprintf(note, "%d D#", octave);
                                break;
                        case (int) Notes::D:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%dD", octave);
+                               sprintf(note, "%d D", octave);
                                break;
                        case (int) Notes::CS:
-                               sprintf(note, "%dC#", octave);
+                               sprintf(note, "%d C#", octave);
                                break;
                        case (int) Notes::C:
-                               sprintf(note, "%dC", octave);
+                               sprintf(note, "%d C", octave);
+                               octave--;
                                break;
                        case (int) Notes::B:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%dB", octave);
+                               sprintf(note, "%d B", octave);
                                break;
                        case (int) Notes::AS:
-                               sprintf(note, "%dA#", octave);
+                               sprintf(note, "%d A#", octave);
                                break;
                        case (int) Notes::A:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%dA", octave);
+                               sprintf(note, "%d A", octave);
                                break;
                        case (int) Notes::GS:
-                               sprintf(note, "%dG#", octave);
-                               octave--;
+                               sprintf(note, "%d G#", octave);
                                break;
                }
 
index da30c69a95489fa76eab9403eba2a82461bf34a7..a433b44282deb2ddd8a94a96d1dcd5bc99cc5e00 100644 (file)
@@ -9,14 +9,14 @@
  * Shows a resize cursor when hovered over.
  * Assumes:
  *     - Parent is an Fl_Scroll
- *     - All children of Fl_Scroll are vertically arranged
+ *     - All children of Fl_Scroll are m_vertically arranged
  *     - The widget above us has a bottom edge touching our top edge
  *       ie. (w->y()+w->h() == this->y())
  *
  * When this widget is dragged:
  *     - The widget above us (with a common edge) will be /resized/
- *       vertically
- *     - All children below us will be /moved/ vertically
+ *       m_vertically
+ *     - All children below us will be /moved/ m_vertically
  *
  * -----------------------------------------------------------------------------
  *
 #include <FL/Fl.H>
 #include <FL/Fl_Scroll.H>
 #include <FL/fl_draw.H>
+#include "../../../core/const.h"
 #include "resizerBar.h"
 
 
-geResizerBar::geResizerBar(int X,int Y,int W,int H, bool vertical)
-  : Fl_Box(X,Y,W,H), vertical(vertical)
+geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type)
+  : Fl_Box   (X, Y, W, H), 
+    m_type   (type),
+    m_minSize(minSize),
+    m_lastPos(0),
+    m_hover  (false)
 {
-  last_y = 0;
-  min_h  = 30;
-  if (vertical) {
-    orig_h = H;
+  if (m_type == VERTICAL) {
+    m_origSize = H;
     labelsize(H);
   }
   else {
-    orig_h = W;
+    m_origSize = W;
     labelsize(W);
   }
-  align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
+  align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
   labelfont(FL_COURIER);
   visible_focus(0);
 }
@@ -69,12 +72,12 @@ geResizerBar::geResizerBar(int X,int Y,int W,int H, bool vertical)
 /* -------------------------------------------------------------------------- */
 
 
-void geResizerBar::HandleDrag(int diff)
+void geResizerBar::handleDrag(int diff)
 {
-  Fl_Scroll *grp = static_cast<Fl_Scroll*>(parent());
+  Fl_Scrollgrp = static_cast<Fl_Scroll*>(parent());
   int top;
   int bot;
-  if (vertical) {
+  if (m_type == VERTICAL) {
     top = y();
     bot = y()+h();
   }
@@ -87,21 +90,21 @@ void geResizerBar::HandleDrag(int diff)
   //    Possibly clamp 'diff' if widget would get too small..
 
   for (int t=0; t<grp->children(); t++) {
-    Fl_Widget *wd = grp->child(t);
-    if (vertical) {
-      if ((wd->y()+wd->h()) == top) {                           // found widget directly above?
-        if ((wd->h()+diff) < min_h)
-          diff = wd->h() - min_h;                              // clamp
-        wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);       // change height
-        break;                                                // done with first pass
+    Fl_Widgetwd = grp->child(t);
+    if (m_type == VERTICAL) {
+      if ((wd->y()+wd->h()) == top) {                          // found widget directly above?
+        if ((wd->h()+diff) < m_minSize)
+          diff = wd->h() - m_minSize;                          // clamp
+        wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);   // change height
+        break;                                                 // done with first pass
       }
     }
     else {
-      if ((wd->x()+wd->w()) == top) {                           // found widget directly above?
-        if ((wd->w()+diff) < min_h)
-          diff = wd->w() - min_h;                              // clamp
-        wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());       // change height
-        break;                                                // done with first pass
+      if ((wd->x()+wd->w()) == top) {                          // found widget directly above?
+        if ((wd->w()+diff) < m_minSize)
+          diff = wd->w() - m_minSize;                          // clamp
+        wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());   // change height
+        break;                                                 // done with first pass
       }
     }
   }
@@ -109,10 +112,10 @@ void geResizerBar::HandleDrag(int diff)
   // Second pass: find widgets below us, move based on clamped diff
 
   for (int t=0; t<grp->children(); t++) {
-    Fl_Widget *wd = grp->child(t);
-    if (vertical) {
+    Fl_Widgetwd = grp->child(t);
+    if (m_type == VERTICAL) {
       if (wd->y() >= bot)                                     // found widget below us?
-        wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());      // change position
+        wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());  // change position
     }
     else {
       if (wd->x() >= bot)
@@ -122,7 +125,7 @@ void geResizerBar::HandleDrag(int diff)
 
   // Change our position last
 
-  if (vertical)
+  if (m_type == VERTICAL)
     resize(x(), y()+diff, w(), h());
   else
     resize(x()+diff, y(), w(), h());
@@ -135,11 +138,21 @@ void geResizerBar::HandleDrag(int diff)
 /* -------------------------------------------------------------------------- */
 
 
+void geResizerBar::draw()
+{
+       Fl_Box::draw();
+       fl_rectf(x(), y(), w(), h(), m_hover ? G_COLOR_GREY_2 : G_COLOR_GREY_1);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 int geResizerBar::handle(int e)
 {
   int ret = 0;
   int this_y;
-  if (vertical)
+  if (m_type == VERTICAL)
     this_y = Fl::event_y_root();
   else
     this_y = Fl::event_x_root();
@@ -149,19 +162,23 @@ int geResizerBar::handle(int e)
       break;
     case FL_ENTER:
       ret = 1;
-      fl_cursor(vertical ? FL_CURSOR_NS : FL_CURSOR_WE);
+      fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
+      m_hover = true;
+      redraw();
       break;
     case FL_LEAVE:
       ret = 1;
       fl_cursor(FL_CURSOR_DEFAULT);
+      m_hover = false;
+      redraw();
       break;
     case FL_PUSH:
       ret = 1;
-      last_y = this_y;
+      m_lastPos = this_y;
       break;
     case FL_DRAG:
-      HandleDrag(this_y-last_y);
-      last_y = this_y;
+      handleDrag(this_y-m_lastPos);
+      m_lastPos = this_y;
       ret = 1;
       break;
     default: break;
@@ -173,10 +190,19 @@ int geResizerBar::handle(int e)
 /* -------------------------------------------------------------------------- */
 
 
-void geResizerBar::resize(int X,int Y,int W,int H)
+int geResizerBar::getMinSize() const
+{ 
+       return m_minSize; 
+} 
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geResizerBar::resize(int x, int y, int w, int h)
 {
-  if (vertical)
-    Fl_Box::resize(X,Y,W,orig_h);                                // height of resizer stays constant size
-  else
-    Fl_Box::resize(X,Y,orig_h,H);
+       if (m_type == VERTICAL)
+               Fl_Box::resize(x, y, w, m_origSize); // Height of resizer stays constant size
+       else
+               Fl_Box::resize(x, y, m_origSize, h);
 }
index 74f5bbfac24f5ec129235103e10bffe59b7af659..4308ddbf1e961c729f35edcef51bfdd64f134651 100644 (file)
@@ -52,28 +52,26 @@ class geResizerBar : public Fl_Box
 {
 private:
 
-  /* TODO - use more general variable names
-   * (last_y -> last_?, min_h -> min_?, ...) */
+       bool m_type;
+       int  m_origSize;
+       int  m_minSize;
+       int  m_lastPos;
+       bool m_hover;
 
-  bool vertical;
-       int  orig_h;
-       int  last_y;
-       int  min_h;   // min height for widget above us
-
-       void HandleDrag(int diff);
+       void handleDrag(int diff);
 
 public:
 
- /* 'vertical' defines the bar movement. Vertical=true: the bar moves
-  * vertically (up and down). */
+       static const int HORIZONTAL = 0;
+       static const int VERTICAL   = 1;
 
-       geResizerBar(int x, int y, int w, int h, bool vertical=true);
+       geResizerBar(int x, int y, int w, int h, int minSize, bool type=VERTICAL);
 
-  inline void setMinSize(int val) { min_h = val; }
-  inline int  getMinSize()        { return min_h; }
+       int handle(int e) override;
+       void draw() override;
 
-  int  handle(int e);
-  void resize(int x, int y, int w, int h);
+       int getMinSize() const;
+       void resize(int x, int y, int w, int h);
 };
 
 
index 8a59077c5b0706d2df92cf6cbd9cb2fba03e6c8f..d226c1fdbaadb7918efd16b86a48a6bfe9e58696 100644 (file)
@@ -36,7 +36,9 @@
 #include "../../../dialogs/gd_pluginList.h"
 #include "../../basics/idButton.h"
 #include "../../basics/dial.h"
+#include "../../basics/statusButton.h"
 #include "column.h"
+#include "channelStatus.h"
 #include "channelButton.h"
 #include "channel.h"
 
@@ -49,8 +51,8 @@ using namespace giada::m;
 
 geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch)
  : Fl_Group(X, Y, W, H, nullptr),
-   ch      (ch),
-   type    (type)
+        ch      (ch),
+        type    (type)
 {
 }
 
@@ -72,7 +74,7 @@ void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_o
 
 void geChannel::__cb_arm()
 {
-  glue_toggleArm(ch, true);
+       glue_toggleArm(ch, true);
 }
 
 
@@ -141,7 +143,7 @@ void geChannel::blink()
        if (gu_getBlinker() > 6)
                mainButton->setPlayMode();
        else
-    mainButton->setDefaultMode();
+               mainButton->setDefaultMode();
 }
 
 
@@ -150,36 +152,36 @@ void geChannel::blink()
 
 void geChannel::setColorsByStatus(int playStatus, int recStatus)
 {
-  switch (playStatus) {
-    case STATUS_OFF:
-    case STATUS_EMPTY:
-               mainButton->setDefaultMode();
-      button->imgOn  = channelPlay_xpm;
-      button->imgOff = channelStop_xpm;
-      button->redraw();
-      break;
-    case STATUS_PLAY:
-      mainButton->setPlayMode();
-      button->imgOn  = channelStop_xpm;
-      button->imgOff = channelPlay_xpm;
-      button->redraw();
-      break;
-    case STATUS_WAIT:
-      blink();
-      break;
-    case STATUS_ENDING:
-      mainButton->setEndingMode();
-      break;
-  }
-
-  switch (recStatus) {
-    case REC_WAITING:
-      blink();
-      break;
-    case REC_ENDING:
-      mainButton->setEndingMode();
-      break;
-  }
+       switch (playStatus) {
+               case STATUS_OFF:
+               case STATUS_EMPTY:
+                       mainButton->setDefaultMode();
+                       button->imgOn  = channelPlay_xpm;
+                       button->imgOff = channelStop_xpm;
+                       button->redraw();
+                       break;
+               case STATUS_PLAY:
+                       mainButton->setPlayMode();
+                       button->imgOn  = channelStop_xpm;
+                       button->imgOff = channelPlay_xpm;
+                       button->redraw();
+                       break;
+               case STATUS_WAIT:
+                       blink();
+                       break;
+               case STATUS_ENDING:
+                       mainButton->setEndingMode();
+                       break;
+       }
+
+       switch (recStatus) {
+               case REC_WAITING:
+                       blink();
+                       break;
+               case REC_ENDING:
+                       mainButton->setEndingMode();
+                       break;
+       }
 }
 
 
@@ -188,31 +190,32 @@ void geChannel::setColorsByStatus(int playStatus, int recStatus)
 
 void geChannel::packWidgets()
 {
-  /* Count visible widgets and resize mainButton according to how many widgets
-  are visible. */
-
-  int visibles = 0;
-  for (int i=0; i<children(); i++) {
-    child(i)->size(20, 20);  // also normalize widths
-    if (child(i)->visible())
-      visibles++;
-  }
-  mainButton->size(w() - ((visibles - 1) * (24)), 20);  // -1: exclude itself
-
-  /* Reposition everything else */
-
-  for (int i=1, p=0; i<children(); i++) {
-    if (!child(i)->visible())
-      continue;
-    for (int k=i-1; k>=0; k--) // Get the first visible item prior to i
-      if (child(k)->visible()) {
-        p = k;
-        break;
-      }
-    child(i)->position(child(p)->x() + child(p)->w() + 4, y());
-  }
-
-  init_sizes(); // Resets the internal array of widget sizes and positions
+       /* Count visible widgets and resize mainButton according to how many widgets
+       are visible. */
+
+       int visibles = 0;
+       for (int i=0; i<children(); i++) {
+               child(i)->size(MIN_ELEM_W, child(i)->h());  // also normalize widths
+               if (child(i)->visible())
+                       visibles++;
+       }
+       mainButton->size(w() - ((visibles - 1) * (MIN_ELEM_W + G_GUI_INNER_MARGIN)),   // -1: exclude itself
+               mainButton->h());
+
+       /* Reposition everything else */
+
+       for (int i=1, p=0; i<children(); i++) {
+               if (!child(i)->visible())
+                       continue;
+               for (int k=i-1; k>=0; k--) // Get the first visible item prior to i
+                       if (child(k)->visible()) {
+                               p = k;
+                               break;
+                       }
+               child(i)->position(child(p)->x() + child(p)->w() + G_GUI_INNER_MARGIN, child(i)->y());
+       }
+
+       init_sizes(); // Resets the internal array of widget sizes and positions
 }
 
 
@@ -239,3 +242,33 @@ int geChannel::handleKey(int e, int key)
 
        return ret;
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::changeSize(int H)
+{
+       size(w(), H);
+       
+       int Y = y() + (H / 2 - (G_GUI_UNIT / 2));
+
+       button->resize(x(), Y, w(), G_GUI_UNIT);
+       arm->resize(x(), Y, w(), G_GUI_UNIT);   
+       mainButton->resize(x(), y(), w(), H);
+       mute->resize(x(), Y, w(), G_GUI_UNIT);
+       solo->resize(x(), Y, w(), G_GUI_UNIT);
+       vol->resize(x(), Y, w(), G_GUI_UNIT);
+#ifdef WITH_VST
+       fx->resize(x(), Y, w(), G_GUI_UNIT);
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geChannel::getSize()
+{
+       return h();
+}
index fd1efd9bb5003354b91594b1540a11736c453f3c..04cbfdd8a6229bc36541accd5b779eb8caf1deb5 100644 (file)
@@ -61,12 +61,14 @@ protected:
        static const int BREAK_ARM          = 168;
 #endif
 
-       static void cb_arm           (Fl_Widget *v, void *p);
-       static void cb_mute          (Fl_Widget *v, void *p);
-       static void cb_solo          (Fl_Widget *v, void *p);
-       static void cb_changeVol     (Fl_Widget *v, void *p);
+       static const int MIN_ELEM_W = 20;
+
+       static void cb_arm           (Fl_Widget* v, void* p);
+       static void cb_mute          (Fl_Widget* v, void* p);
+       static void cb_solo          (Fl_Widget* v, void* p);
+       static void cb_changeVol     (Fl_Widget* v, void* p);
 #ifdef WITH_VST
-               static void cb_openFxWindow(Fl_Widget *v, void *p);
+               static void cb_openFxWindow(Fl_Widget* v, void* p);
 #endif
 
        inline void __cb_mute();
@@ -99,7 +101,7 @@ protected:
 
 public:
 
-       geChannel(int x, int y, int w, int h, int type, Channel *ch);
+       geChannel(int x, int y, int w, int h, int type, Channelch);
 
        /* reset
         * reset channel to initial status. */
@@ -117,6 +119,11 @@ public:
 
        virtual void refresh() = 0;
 
+       /* changeSize
+       Changes channel's size according to a template (x1, x2, ...). */
+
+       virtual void changeSize(int h);
+
        /* keypress
         * what to do when the corresponding key is pressed. */
 
@@ -128,17 +135,19 @@ public:
 
        int getColumnIndex();
 
-       Channel *ch;
-
-       geIdButton      *button;
-       geChannelStatus *status;
-       geButton              *arm;
-       geChannelButton *mainButton;
-       geButton              *mute;
-       geButton              *solo;
-       geDial           *vol;
+       int getSize();
+
+       Channel* ch;
+       geIdButton*      button;
+       geChannelStatus* status;
+       geButton*        arm;
+       geChannelButton* mainButton;
+       geButton*        mute;
+       geButton*        solo;
+       geDial*          vol;
 #ifdef WITH_VST
-       geStatusButton  *fx;
+       geStatusButton*  fx;
 #endif
 
        int type;
index 111ad4477b2ac85a419d5641b0e2eb98fdd71c6d..18a88bc6ac784ecd773bdb6bfb58d1f6783dfd78 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include <FL/fl_draw.H>
 #include <FL/Fl_Menu_Button.H>
 #include "../../../../core/sampleChannel.h"
+#include "../../../../core/midiChannel.h"
 #include "../../../../glue/channel.h"
 #include "../../../../utils/log.h"
 #include "../../../../utils/fs.h"
 
 
 using std::vector;
+using std::string;
 
 
-geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard *parent)
-       : Fl_Group(X, Y, W, H), parent(parent), index(index)
+geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard* parent)
+       : Fl_Group(X, Y, W, H), 
+               m_parent(parent), 
+               m_index (index)
 {
-  /* geColumn does a bit of a mess: we pass a pointer to its parent (geKeyboard) and
-  the geColumn itself deals with the creation of another widget, outside geColumn
-  and inside geKeyboard, which handles the vertical resize bar (geResizerBar).
-  The resizer cannot stay inside geColumn: it needs a broader view on the other
-  side widgets. The view can be obtained from geKeyboard only (the upper level).
-  Unfortunately, parent() can be nullptr: at this point (i.e the constructor)
-  geColumn is still detached from any parent. We use a custom geKeyboard *parent
-  instead. */
+       /* geColumn does a bit of a mess: we pass a pointer to its m_parent (geKeyboard) and
+       the geColumn itself deals with the creation of another widget, outside geColumn
+       and inside geKeyboard, which handles the vertical resize bar (geResizerBar).
+       The resizer cannot stay inside geColumn: it needs a broader view on the other
+       side widgets. The view can be obtained from geKeyboard only (the upper level).
+       Unfortunately, parent() can be nullptr: at this point (i.e the constructor)
+       geColumn is still detached from any parent. We use a custom geKeyboard *parent
+       instead. */
 
        begin();
-       addChannelBtn = new geButton(x(), y(), w(), 20, "Add new channel");
+       m_addChannelBtn = new geButton(x(), y(), w(), G_GUI_UNIT, "Add new channel");
        end();
 
-  resizer = new geResizerBar(x()+w(), y(), 16, h(), false);
-  resizer->setMinSize(G_MIN_COLUMN_WIDTH);
-  parent->add(resizer);
+       m_resizer = new geResizerBar(x()+w(), y(), G_GUI_OUTER_MARGIN * 2, h(), 
+               G_MIN_COLUMN_WIDTH, geResizerBar::HORIZONTAL);
+       m_parent->add(m_resizer);
 
-       addChannelBtn->callback(cb_addChannel, (void*)this);
+       m_addChannelBtn->callback(cb_addChannel, (void*)this);
 }
 
 
@@ -73,10 +78,10 @@ geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard *parent)
 
 geColumn::~geColumn()
 {
-  /* FIXME - this could actually cause a memory leak. resizer is
-  just removed, not deleted. But we cannot delete it right now. */
+       /* FIXME - this could actually cause a memory leak. m_resizer is
+       just removed, not deleted. But we cannot delete it right now. */
 
-  parent->remove(resizer);
+       m_parent->remove(m_resizer);
 }
 
 
@@ -99,14 +104,15 @@ int geColumn::handle(int e)
                        return 1;
                }
                case FL_PASTE: {              // handle actual drop (paste) operation
-                       vector<std::string> paths;
+                       vector<string> paths;
                        gu_split(Fl::event_text(), "\n", &paths);
                        bool fails = false;
                        int result = 0;
-                       for (unsigned i=0; i<paths.size(); i++) {
-                               gu_log("[geColumn::handle] loading %s...\n", paths.at(i).c_str());
-                               SampleChannel *c = (SampleChannel*) glue_addChannel(index, CHANNEL_SAMPLE);
-                               result = glue_loadChannel(c, gu_stripFileUrl(paths.at(i)).c_str());
+                       for (string& path : paths) {
+                               gu_log("[geColumn::handle] loading %s...\n", path.c_str());
+                               SampleChannel* c = static_cast<SampleChannel*>(glue_addChannel(
+                                       m_index, CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+                               result = glue_loadChannel(c, gu_stripFileUrl(path));
                                if (result != G_RES_OK) {
                                        deleteChannel(c->guiChannel);
                                        fails = true;
@@ -116,7 +122,7 @@ int geColumn::handle(int e)
                                if (paths.size() > 1)
                                        gdAlert("Some files were not loaded successfully.");
                                else
-                                       parent->printChannelMessage(result);
+                                       m_parent->printChannelMessage(result);
                        }
                        return 1;
                }
@@ -134,21 +140,23 @@ int geColumn::handle(int e)
 
 void geColumn::resize(int X, int Y, int W, int H)
 {
-  /* resize all children */
+       /* Resize all children, including "add channel" button. */
 
-  int ch = children();
-  for (int i=0; i<ch; i++) {
-    Fl_Widget *c = child(i);
-    c->resize(X, Y + (i * (c->h() + 4)), W, c->h());
-  }
+       for (int i=0; i<children(); i++) {
+               Fl_Widget* wgCurr = child(i);
+               Fl_Widget* wgPrev = i == 0 ? nullptr : child(i - 1);
+               wgCurr->resize(X, (wgPrev == nullptr ? Y : wgPrev->y() + wgPrev->h() + G_GUI_INNER_MARGIN), 
+                       W, wgCurr->h());
+       }
 
-  /* resize group itself */
+       /* Resize group itself. Must use internal functions, resize() would trigger
+       infinite recursion. */
 
-  x(X); y(Y); w(W); h(H);
+       x(X); y(Y); w(W); h(H);
 
-  /* resize resizerBar */
+       /* Resize resizerBar. */
 
-  resizer->size(16, H);
+       m_resizer->size(G_GUI_OUTER_MARGIN * 2, H);
 }
 
 
@@ -158,7 +166,7 @@ void geColumn::resize(int X, int Y, int W, int H)
 void geColumn::refreshChannels()
 {
        for (int i=1; i<children(); i++)
-               ((geChannel*) child(i))->refresh();
+               static_cast<geChannel*>(child(i))->refresh();
 }
 
 
@@ -167,41 +175,57 @@ void geColumn::refreshChannels()
 
 void geColumn::draw()
 {
-       fl_color(fl_rgb_color(27, 27, 27));
+       fl_color(G_COLOR_GREY_1_5);
        fl_rectf(x(), y(), w(), h());
 
-  /* call draw and then redraw in order to avoid channel corruption when
-  scrolling horizontally */
+       /* call draw and then redraw in order to avoid channel corruption when
+       scrolling horizontally */
 
-  for (int i=0; i<children(); i++) {
-    child(i)->draw();
-    child(i)->redraw();
-  }
+       for (int i=0; i<children(); i++) {
+               child(i)->draw();
+               child(i)->redraw();
+       }
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geColumn::cb_addChannel(Fl_Widget *v, void *p) { ((geColumn*)p)->__cb_addChannel(); }
+void geColumn::cb_addChannel(Fl_Widget* v, void* p) { ((geColumn*)p)->__cb_addChannel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geColumn::repositionChannels()
+{
+       int totalH = 0;
+       for (int i=0; i<children(); i++)
+               totalH += child(i)->h() + G_GUI_INNER_MARGIN;
+       resize(x(), y(), w(), totalH + 66); // evil space for drag n drop
+}
 
 
 /* -------------------------------------------------------------------------- */
 
 
-geChannel *geColumn::addChannel(Channel *ch)
+geChannel* geColumn::addChannel(Channel* ch, int size)
 {
-       int currentY = y() + children() * 24;
-       geChannel *gch = nullptr;
+       geChannel* gch = nullptr;
+
+       /* All geChannels are added with y=0. That's not a problem, they will be 
+       repositioned later on during geColumn::resize(). */
+
        if (ch->type == CHANNEL_SAMPLE)
-               gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch);
+               gch = new geSampleChannel(x(), 0, w(), size, static_cast<SampleChannel*>(ch));
        else
-               gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch);
+               gch = new geMidiChannel(x(), 0, w(), size, static_cast<MidiChannel*>(ch));
 
        add(gch);
-  resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop
-  gch->redraw();    // avoid corruption
-       parent->redraw(); // redraw Keyboard
+
+       repositionChannels();
+       gch->redraw();    // fix corruption
+       m_parent->redraw(); // redraw Keyboard
        return gch;
 }
 
@@ -209,23 +233,17 @@ geChannel *geColumn::addChannel(Channel *ch)
 /* -------------------------------------------------------------------------- */
 
 
-void geColumn::deleteChannel(geChannel *gch)
+void geColumn::deleteChannel(geChannelgch)
 {
        gch->hide();
        remove(gch);
        delete gch;
 
-       /* reposition all other channels and resize this group */
        /** TODO
         * reposition is useless when called by geColumn::clear(). Add a new
         * parameter to skip the operation */
 
-       for (int i=0; i<children(); i++) {
-               gch = (geChannel*) child(i);
-               gch->position(gch->x(), y()+(i*24));
-       }
-       size(w(), children() * 24 + 66);  // evil space for drag n drop
-       redraw();
+       repositionChannels();
 }
 
 
@@ -234,10 +252,10 @@ void geColumn::deleteChannel(geChannel *gch)
 
 void geColumn::__cb_addChannel()
 {
-       gu_log("[geColumn::__cb_addChannel] index = %d\n", index);
+       gu_log("[geColumn::__cb_addChannel] m_index = %d\n", m_index);
        int type = openTypeMenu();
        if (type)
-               glue_addChannel(index, type);
+               glue_addChannel(m_index, type, G_GUI_CHANNEL_H_1);
 }
 
 
@@ -252,7 +270,7 @@ int geColumn::openTypeMenu()
                {0}
        };
 
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       Fl_Menu_Buttonb = new Fl_Menu_Button(0, 0, 100, 50);
        b->box(G_CUSTOM_BORDER_BOX);
        b->textsize(G_GUI_FONT_SIZE_BASE);
        b->textcolor(G_COLOR_LIGHT_2);
@@ -279,7 +297,7 @@ void geColumn::clear(bool full)
        else {
                while (children() >= 2) {  // skip "add new channel" btn
                        int i = children()-1;
-                       deleteChannel((geChannel*)child(i));
+                       deleteChannel(static_cast<geChannel*>(child(i)));
                }
        }
 }
@@ -288,11 +306,16 @@ void geColumn::clear(bool full)
 /* -------------------------------------------------------------------------- */
 
 
-Channel *geColumn::getChannel(int i)
+ChannelgeColumn::getChannel(int i)
 {
-  geChannel *gch = (geChannel*) child(i);
-  if (gch->type == CHANNEL_SAMPLE)
-    return ((geSampleChannel*) child(i))->ch;
-  else
-    return ((geMidiChannel*) child(i))->ch;
+       return static_cast<geChannel*>(child(i + 1))->ch;  // Skip "add channel"
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geColumn::getIndex()       { return m_index; }
+void geColumn::setIndex(int i) { m_index = i; }
+bool geColumn::isEmpty()       { return children() == 1; }
+int geColumn::countChannels()  { return children() - 1; }
\ No newline at end of file
index 8c1152821733d0b639cab935a51ff245d5d63a7a..b6ea1d442565abae73ff5ce62568f6d754246d51 100644 (file)
@@ -43,64 +43,55 @@ class geColumn : public Fl_Group
 {
 private:
 
-       static void cb_addChannel  (Fl_Widget *v, void *p);
+       static void cb_addChannel  (Fl_Widget* v, void* p);
        inline void __cb_addChannel();
 
        int openTypeMenu();
 
-       geButton    *addChannelBtn;
-       geResizerBar *resizer;
-       geKeyboard  *parent;
+       geButton*     m_addChannelBtn;
+       geResizerBar* m_resizer;
+       geKeyboard*   m_parent;
 
-       int index;
+       int m_index;
 
 public:
 
-       geColumn(int x, int y, int w, int h, int index, geKeyboard *parent);
+       geColumn(int x, int y, int w, int h, int index, geKeyboardparent);
        ~geColumn();
 
        /* addChannel
-        * add a new channel in this column and set the internal pointer
-        * to channel to 'ch'. */
+       Adds a new channel in this column and set the internal pointer to channel 
+       to 'ch'. */
 
-       geChannel *addChannel(Channel *ch);
+       geChannel* addChannel(Channel* ch, int size);
 
-       /* handle */
+       int handle(int e) override;
+       void draw() override;
+  void resize(int x, int y, int w, int h) override;
 
-       int handle(int e);
-
-  /* resize
-   * custom resize behavior. */
+       /* clear
+       Removes all channels from the column. If full==true, delete also the "add new 
+       channel" button. */
 
-  void resize(int x, int y, int w, int h);
+       void clear(bool full=false);
 
        /* deleteChannel
-        * remove the channel 'gch' from this column. */
+       Removes the channel 'gch' from this column. */
 
-       void deleteChannel(geChannel *gch);
+       void deleteChannel(geChannel* gch);
+
+       void repositionChannels();
 
        /* refreshChannels
-        * update channels' graphical statues. Called on each GUI cycle. */
+       Updates channels' graphical statues. Called on each GUI cycle. */
 
        void refreshChannels();
 
-  /* getChannel */
-
-  Channel *getChannel(int i);
-
-       /* clear
-        * remove all channels from the column. If full==true, delete also the
-        * "add new channel" button. This method ovverrides the inherited one
-        * from Fl_Group. */
-
-       void clear(bool full=false);
-
-       void draw();
-
-       inline int  getIndex()      { return index; }
-       inline void setIndex(int i) { index = i; }
-       inline bool isEmpty()       { return children() == 1; }
-  inline int  countChannels() { return children(); }
+       Channel* getChannel(int i);
+       int getIndex();
+       void setIndex(int i);
+       bool isEmpty();   
+  int countChannels();
 };
 
 
index f76b216b48e8302f9ecc08a96cf039a82aba301c..e5e0f3c7ebfc825b43a8d1e94b19cc9f06becf73 100644 (file)
@@ -165,7 +165,7 @@ void geKeyboard::cb_addColumn(Fl_Widget* v, void* p)
 /* -------------------------------------------------------------------------- */
 
 
-geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, bool build)
+geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, int size, bool build)
 {
        geColumn* col = getColumnByIndex(colIndex);
 
@@ -179,8 +179,9 @@ geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, bool build)
                gu_log("[geKeyboard::addChannel] created new column with index=%d\n", colIndex);
        }
 
-       gu_log("[geKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
-       return col->addChannel(ch);
+       gu_log("[geKeyboard::addChannel] add to column with index=%d, size=%d\n", 
+               col->getIndex(), size);
+       return col->addChannel(ch, size);
 }
 
 
@@ -313,6 +314,8 @@ void geKeyboard::printChannelMessage(int res)
                gdAlert("Unable to read this sample.");
        else if (res == G_RES_ERR_PATH_TOO_LONG)
                gdAlert("File path too long.");
+       else if (res == G_RES_ERR_NO_DATA)
+               gdAlert("No file specified.");
        else
                gdAlert("Unknown error.");
 }
index 89c3b4e359f6017af398e7de20454d3b198a15d2..432364ef3e05dbfaa0b708c13864f8fbc0061853 100644 (file)
@@ -85,12 +85,11 @@ public:
        void init();
 
        /* addChannel
-        * add a new channel to geChannels. Used by callbacks and during
-        * patch loading. Requires Channel (and not geChannel). If build is
-        * set to true, also generate the corresponding column if column (index) does
-        * not exist yet. */
+       Adds a new channel to geChannels. Used by callbacks and during patch loading. 
+       Requires Channel (and not geChannel). If build is set to true, also generate 
+       the corresponding column if column (index) does not exist yet. */
 
-       geChannel* addChannel(int column, Channel* ch, bool build=false);
+       geChannel* addChannel(int column, Channel* ch, int size, bool build=false);
 
        /* addColumn
         * add a new column to the top of the stack. */
index 2261bcd511535b3e3edef23660f76d714ec7f29a..64e9b9db9adc55a37fa96b8b251c0f518f08c8eb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) G_GUI_UNIT10-G_GUI_UNIT17 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -45,6 +45,7 @@
 #include "../../basics/idButton.h"
 #include "../../basics/statusButton.h"
 #include "../../basics/dial.h"
+#include "column.h"
 #include "midiChannel.h"
 
 
@@ -58,15 +59,21 @@ namespace
 {
 enum class Menu
 {
-  EDIT_ACTIONS = 0,
-  CLEAR_ACTIONS,
-  CLEAR_ACTIONS_ALL,
-  __END_SUBMENU__,
-  SETUP_KEYBOARD_INPUT,
-  SETUP_MIDI_INPUT,
-  SETUP_MIDI_OUTPUT,
-  CLONE_CHANNEL,
-  DELETE_CHANNEL
+       EDIT_ACTIONS = 0,
+       CLEAR_ACTIONS,
+       CLEAR_ACTIONS_ALL,
+       __END_CLEAR_ACTION_SUBMENU__,
+       SETUP_KEYBOARD_INPUT,
+       SETUP_MIDI_INPUT,
+       SETUP_MIDI_OUTPUT,
+       RESIZE,
+       RESIZE_H1,
+       RESIZE_H2,
+       RESIZE_H3,
+       RESIZE_H4,
+       __END_RESIZE_SUBMENU__,
+       CLONE_CHANNEL,
+       DELETE_CHANNEL
 };
 
 
@@ -75,37 +82,55 @@ enum class Menu
 
 void menuCallback(Fl_Widget *w, void *v)
 {
-  geMidiChannel *gch = static_cast<geMidiChannel*>(w);
-  Menu selectedItem = (Menu) (intptr_t) v;
-
-  switch (selectedItem)
-  {
-    case Menu::CLEAR_ACTIONS:
-    case Menu::__END_SUBMENU__:
-      break;
-    case Menu::EDIT_ACTIONS:
-      gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
-      break;
-    case Menu::CLEAR_ACTIONS_ALL:
-      glue_clearAllActions(gch);
-      break;
-    case Menu::SETUP_KEYBOARD_INPUT:
-      gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
-      break;
-    case Menu::SETUP_MIDI_INPUT:
-      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);
-      break;
-    case Menu::CLONE_CHANNEL:
-      glue_cloneChannel(gch->ch);
-      break;
-    case Menu::DELETE_CHANNEL:
-      glue_deleteChannel(gch->ch);
-      break;
-  }
+       geMidiChannel *gch = static_cast<geMidiChannel*>(w);
+       Menu selectedItem = (Menu) (intptr_t) v;
+
+       switch (selectedItem)
+       {
+               case Menu::CLEAR_ACTIONS:
+               case Menu::__END_CLEAR_ACTION_SUBMENU__:
+               case Menu::RESIZE:
+               case Menu::__END_RESIZE_SUBMENU__:
+                       break;
+               case Menu::EDIT_ACTIONS:
+                       gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+                       break;
+               case Menu::CLEAR_ACTIONS_ALL:
+                       glue_clearAllActions(gch);
+                       break;
+               case Menu::SETUP_KEYBOARD_INPUT:
+                       gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
+                       break;
+               case Menu::SETUP_MIDI_INPUT:
+                       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);
+                       break;
+               case Menu::RESIZE_H1:
+                       gch->changeSize(G_GUI_CHANNEL_H_1);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;          
+               case Menu::RESIZE_H2:
+                       gch->changeSize(G_GUI_CHANNEL_H_2);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;          
+               case Menu::RESIZE_H3:
+                       gch->changeSize(G_GUI_CHANNEL_H_3);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;          
+               case Menu::RESIZE_H4:
+                       gch->changeSize(G_GUI_CHANNEL_H_4);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;
+               case Menu::CLONE_CHANNEL:
+                       glue_cloneChannel(gch->ch);
+                       break;
+               case Menu::DELETE_CHANNEL:
+                       glue_deleteChannel(gch->ch);
+                       break;
+       }
 }
 
 }; // {namespace}
@@ -120,26 +145,26 @@ geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch)
        begin();
 
 #if defined(WITH_VST)
-  int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
+       int delta = 144; // (6 widgets * G_GUI_UNIT) + (6 paddings * 4)
 #else
-       int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
+       int delta = 120; // (5 widgets * G_GUI_UNIT) + (5 paddings * 4)
 #endif
 
-       button     = new geIdButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
-       arm        = new geButton(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
-       mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --");
-       mute       = new geButton(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo       = new geButton(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+       button     = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+       arm        = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
+       mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, H, "-- MIDI --");
+       mute       = new geButton(mainButton->x()+mainButton->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", muteOff_xpm, muteOn_xpm);
+       solo       = new geButton(mute->x()+mute->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", soloOff_xpm, soloOn_xpm);
 #if defined(WITH_VST)
-       fx         = new geStatusButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol        = new geDial(fx->x()+fx->w()+4, y(), 20, 20);
+       fx         = new geStatusButton(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+       vol        = new geDial(fx->x()+fx->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
 #else
-       vol        = new geDial(solo->x()+solo->w()+4, y(), 20, 20);
+       vol        = new geDial(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
 #endif
 
        end();
 
-  resizable(mainButton);
+       resizable(mainButton);
 
        update();
 
@@ -164,6 +189,8 @@ geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch)
        vol->callback(cb_changeVol, (void*)this);
 
        ch->guiChannel = this;
+
+       changeSize(H);  // Update size dynamically
 }
 
 
@@ -197,8 +224,14 @@ void geMidiChannel::__cb_openMenu()
                {"Setup keyboard input...", 0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
                {"Setup MIDI input...",     0, menuCallback, (void*) Menu::SETUP_MIDI_INPUT},
                {"Setup MIDI output...",    0, menuCallback, (void*) Menu::SETUP_MIDI_OUTPUT},
-               {"Clone channel",           0, menuCallback, (void*) Menu::CLONE_CHANNEL},
-               {"Delete channel",          0, menuCallback, (void*) Menu::DELETE_CHANNEL},
+               {"Resize",    0, menuCallback, (void*) Menu::RESIZE, FL_SUBMENU},
+                       {"Normal",  0, menuCallback, (void*) Menu::RESIZE_H1},
+                       {"Medium",  0, menuCallback, (void*) Menu::RESIZE_H2},
+                       {"Large",   0, menuCallback, (void*) Menu::RESIZE_H3},
+                       {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
+                       {0},
+               {"Clone channel",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
+               {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
                {0}
        };
 
@@ -213,10 +246,10 @@ void geMidiChannel::__cb_openMenu()
        b->textcolor(G_COLOR_LIGHT_2);
        b->color(G_COLOR_GREY_2);
 
-  const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-  if (m)
-    m->do_callback(this, m->user_data());
-  return;
+       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (m)
+               m->do_callback(this, m->user_data());
+       return;
 }
 
 
@@ -271,7 +304,7 @@ void geMidiChannel::update()
 
 void geMidiChannel::resize(int X, int Y, int W, int H)
 {
-  geChannel::resize(X, Y, W, H);
+       geChannel::resize(X, Y, W, H);
 
        arm->hide();
 #ifdef WITH_VST
index 25de771d7ffa18f450fc1d158827488f83337750..8ed63f0ad5611aa11d54f0f726cc699f5d334376 100644 (file)
@@ -51,11 +51,13 @@ public:
 
        geMidiChannel(int x, int y, int w, int h, MidiChannel *ch);
 
-       void reset   ();
-       void update  ();
-       void refresh ();
-       int  keyPress(int event);  // TODO - move to base class
-       void resize  (int x, int y, int w, int h);
+       void resize(int x, int y, int w, int h) override;
+
+       void reset() override;
+       void update() override;
+       void refresh() override;
+
+       int keyPress(int event);  // TODO - move to base class
 };
 
 
index b22dcc1c536c7cf8c81871819403d73d686c6d8b..15950978e1e2161978d73a6b7e78d802a5018a7e 100644 (file)
 #include "channelMode.h"
 #include "sampleChannelButton.h"
 #include "keyboard.h"
+#include "column.h"
 #include "sampleChannel.h"
 
 
-extern gdMainWindow *G_MainWin;
+extern gdMainWindowG_MainWin;
 
 
 using namespace giada::m;
@@ -66,105 +67,133 @@ namespace
 {
 enum class Menu
 {
-  INPUT_MONITOR = 0,
-  LOAD_SAMPLE,
-  EXPORT_SAMPLE,
-  SETUP_KEYBOARD_INPUT,
-  SETUP_MIDI_INPUT,
-  SETUP_MIDI_OUTPUT,
-  EDIT_SAMPLE,
-  EDIT_ACTIONS,
-  CLEAR_ACTIONS,
-  CLEAR_ACTIONS_ALL,
-  CLEAR_ACTIONS_MUTE,
-  CLEAR_ACTIONS_VOLUME,
-  CLEAR_ACTIONS_START_STOP,
-  __END_SUBMENU__,
-  CLONE_CHANNEL,
-  FREE_CHANNEL,
-  DELETE_CHANNEL
+       INPUT_MONITOR = 0,
+       LOAD_SAMPLE,
+       EXPORT_SAMPLE,
+       SETUP_KEYBOARD_INPUT,
+       SETUP_MIDI_INPUT,
+       SETUP_MIDI_OUTPUT,
+       EDIT_SAMPLE,
+       EDIT_ACTIONS,
+       CLEAR_ACTIONS,
+       CLEAR_ACTIONS_ALL,
+       CLEAR_ACTIONS_MUTE,
+       CLEAR_ACTIONS_VOLUME,
+       CLEAR_ACTIONS_START_STOP,
+       __END_CLEAR_ACTIONS_SUBMENU__,
+       RESIZE,
+       RESIZE_H1,
+       RESIZE_H2,
+       RESIZE_H3,
+       RESIZE_H4,
+       __END_RESIZE_SUBMENU__,
+       CLONE_CHANNEL,
+       FREE_CHANNEL,
+       DELETE_CHANNEL
 };
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void menuCallback(Fl_Widget *w, void *v)
+void menuCallback(Fl_Widget* w, void* v)
 {
-  geSampleChannel *gch = static_cast<geSampleChannel*>(w);
-  Menu selectedItem = (Menu) (intptr_t) v;
-
-  switch (selectedItem) {
-    case Menu::INPUT_MONITOR: {
-      glue_toggleInputMonitor(gch->ch);
-      break;
-    }
-    case Menu::LOAD_SAMPLE: {
-      gdWindow *w = new gdBrowserLoad(conf::browserX, conf::browserY,
-        conf::browserW, conf::browserH, "Browse sample",
-        conf::samplePath.c_str(), glue_loadSample, gch->ch);
-      gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
-      break;
-    }
-    case Menu::EXPORT_SAMPLE: {
-      gdWindow *w = new gdBrowserSave(conf::browserX, conf::browserY,
-        conf::browserW, conf::browserH, "Save sample",
-        conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
-      gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
-               break;
-    }
-    case Menu::SETUP_KEYBOARD_INPUT: {
-               new gdKeyGrabber(gch->ch); // FIXME - use gu_openSubWindow
-               break;
-    }
-    case Menu::SETUP_MIDI_INPUT: {
-      gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
-      break;
-    }
-    case Menu::SETUP_MIDI_OUTPUT: {
-      gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(static_cast<SampleChannel*>(gch->ch)), 0);
-      break;
-    }
-    case Menu::EDIT_SAMPLE: {
-      gu_openSubWindow(G_MainWin, new gdSampleEditor(static_cast<SampleChannel*>(gch->ch)), WID_SAMPLE_EDITOR);
-      break;
-    }
-    case Menu::EDIT_ACTIONS: {
-      gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
-      break;
-    }
-    case Menu::CLEAR_ACTIONS:
-    case Menu::__END_SUBMENU__:
-      break;
-    case Menu::CLEAR_ACTIONS_ALL: {
-      glue_clearAllActions(gch);
-      break;
-    }
-    case Menu::CLEAR_ACTIONS_MUTE: {
-      glue_clearMuteActions(gch);
-      break;
-    }
-    case Menu::CLEAR_ACTIONS_VOLUME: {
-      glue_clearVolumeActions(gch);
-      break;
-    }
-    case Menu::CLEAR_ACTIONS_START_STOP: {
-      glue_clearStartStopActions(gch);
-      break;
-    }
-    case Menu::CLONE_CHANNEL: {
-      glue_cloneChannel(gch->ch);
-      break;
-    }
-    case Menu::FREE_CHANNEL: {
-               glue_freeChannel(gch->ch);
-      break;
-    }
-    case Menu::DELETE_CHANNEL: {
-      glue_deleteChannel(gch->ch);
-      break;
-    }
-  }
+       geSampleChannel* gch = static_cast<geSampleChannel*>(w);
+       Menu selectedItem = (Menu) (intptr_t) v;
+
+       switch (selectedItem) {
+               case Menu::INPUT_MONITOR: {
+                       glue_toggleInputMonitor(gch->ch);
+                       break;
+               }
+               case Menu::LOAD_SAMPLE: {
+                       gdWindow *w = new gdBrowserLoad(conf::browserX, conf::browserY,
+                               conf::browserW, conf::browserH, "Browse sample",
+                               conf::samplePath.c_str(), glue_loadSample, gch->ch);
+                       gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+                       break;
+               }
+               case Menu::EXPORT_SAMPLE: {
+                       gdWindow *w = new gdBrowserSave(conf::browserX, conf::browserY,
+                               conf::browserW, conf::browserH, "Save sample",
+                               conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
+                       gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+                       break;
+               }
+               case Menu::SETUP_KEYBOARD_INPUT: {
+                       new gdKeyGrabber(gch->ch); // FIXME - use gu_openSubWindow
+                       break;
+               }
+               case Menu::SETUP_MIDI_INPUT: {
+                       gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
+                       break;
+               }
+               case Menu::SETUP_MIDI_OUTPUT: {
+                       gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(static_cast<SampleChannel*>(gch->ch)), 0);
+                       break;
+               }
+               case Menu::EDIT_SAMPLE: {
+                       gu_openSubWindow(G_MainWin, new gdSampleEditor(static_cast<SampleChannel*>(gch->ch)), WID_SAMPLE_EDITOR);
+                       break;
+               }
+               case Menu::EDIT_ACTIONS: {
+                       gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+                       break;
+               }
+               case Menu::CLEAR_ACTIONS:
+               case Menu::RESIZE:
+               case Menu::__END_CLEAR_ACTIONS_SUBMENU__:
+               case Menu::__END_RESIZE_SUBMENU__:
+                       break;
+               case Menu::CLEAR_ACTIONS_ALL: {
+                       glue_clearAllActions(gch);
+                       break;
+               }
+               case Menu::CLEAR_ACTIONS_MUTE: {
+                       glue_clearMuteActions(gch);
+                       break;
+               }
+               case Menu::CLEAR_ACTIONS_VOLUME: {
+                       glue_clearVolumeActions(gch);
+                       break;
+               }
+               case Menu::CLEAR_ACTIONS_START_STOP: {
+                       glue_clearStartStopActions(gch);
+                       break;
+               }
+               case Menu::RESIZE_H1: {
+                       gch->changeSize(G_GUI_CHANNEL_H_1);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;
+               }               
+               case Menu::RESIZE_H2: {
+                       gch->changeSize(G_GUI_CHANNEL_H_2);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;
+               }               
+               case Menu::RESIZE_H3: {
+                       gch->changeSize(G_GUI_CHANNEL_H_3);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;
+               }               
+               case Menu::RESIZE_H4: {
+                       gch->changeSize(G_GUI_CHANNEL_H_4);
+                       static_cast<geColumn*>(gch->parent())->repositionChannels();
+                       break;
+               }
+               case Menu::CLONE_CHANNEL: {
+                       glue_cloneChannel(gch->ch);
+                       break;
+               }
+               case Menu::FREE_CHANNEL: {
+                       glue_freeChannel(gch->ch);
+                       break;
+               }
+               case Menu::DELETE_CHANNEL: {
+                       glue_deleteChannel(gch->ch);
+                       break;
+               }
+       }
 }
 
 }; // {namespace}
@@ -173,29 +202,29 @@ void menuCallback(Fl_Widget *w, void *v)
 /* -------------------------------------------------------------------------- */
 
 
-geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch)
-       : geChannel(X, Y, W, H, CHANNEL_SAMPLE, (Channel*) ch)
+geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannelch)
+       : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch)
 {
        begin();
 
-       button      = new geIdButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
-       arm         = new geButton(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
-       status      = new geChannelStatus(arm->x()+arm->w()+4, y(), 20, 20, ch);
-       mainButton  = new geSampleChannelButton(status->x()+status->w()+4, y(), 20, 20, "-- no sample --");
-       readActions = new geButton(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm);
-       modeBox     = new geChannelMode(readActions->x()+readActions->w()+4, y(), 20, 20, ch);
-       mute        = new geButton(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
-       solo        = new geButton(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+       button      = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+       arm         = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
+       status      = new geChannelStatus(arm->x()+arm->w()+4, y(), G_GUI_UNIT, H, ch);
+       mainButton  = new geSampleChannelButton(status->x()+status->w()+4, y(), G_GUI_UNIT, H, "-- no sample --");
+       readActions = new geButton(mainButton->x()+mainButton->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", readActionOff_xpm, readActionOn_xpm);
+       modeBox     = new geChannelMode(readActions->x()+readActions->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, ch);
+       mute        = new geButton(modeBox->x()+modeBox->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", muteOff_xpm, muteOn_xpm);
+       solo        = new geButton(mute->x()+mute->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", soloOff_xpm, soloOn_xpm);
 #ifdef WITH_VST
-       fx          = new geStatusButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
-       vol         = new geDial(fx->x()+fx->w()+4, y(), 20, 20);
+       fx          = new geStatusButton(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+       vol         = new geDial(fx->x()+fx->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
 #else
-       vol         = new geDial(solo->x()+solo->w()+4, y(), 20, 20);
+       vol         = new geDial(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
 #endif
 
        end();
 
-  resizable(mainButton);
+       resizable(mainButton);
 
        update();
 
@@ -224,15 +253,17 @@ geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch)
        vol->callback(cb_changeVol, (void*)this);
 
        ch->guiChannel = this;
+
+       changeSize(H);  // Update size dynamically
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geSampleChannel::cb_button      (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); }
-void geSampleChannel::cb_openMenu    (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); }
-void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); }
+void geSampleChannel::cb_button      (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_button(); }
+void geSampleChannel::cb_openMenu    (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_openMenu(); }
+void geSampleChannel::cb_readActions (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_readActions(); }
 
 
 /* -------------------------------------------------------------------------- */
@@ -260,7 +291,7 @@ void geSampleChannel::__cb_openMenu()
 
        Fl_Menu_Item rclick_menu[] = {
                {"Input monitor",            0, menuCallback, (void*) Menu::INPUT_MONITOR,
-      FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
+                       FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
                {"Load new sample...",       0, menuCallback, (void*) Menu::LOAD_SAMPLE},
                {"Export sample to file...", 0, menuCallback, (void*) Menu::EXPORT_SAMPLE},
                {"Setup keyboard input...",  0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
@@ -274,6 +305,12 @@ void geSampleChannel::__cb_openMenu()
                        {"Volume",     0, menuCallback, (void*) Menu::CLEAR_ACTIONS_VOLUME},
                        {"Start/Stop", 0, menuCallback, (void*) Menu::CLEAR_ACTIONS_START_STOP},
                        {0},
+               {"Resize",    0, menuCallback, (void*) Menu::RESIZE, FL_SUBMENU},
+                       {"Normal",  0, menuCallback, (void*) Menu::RESIZE_H1},
+                       {"Medium",  0, menuCallback, (void*) Menu::RESIZE_H2},
+                       {"Large",   0, menuCallback, (void*) Menu::RESIZE_H3},
+                       {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
+                       {0},
                {"Clone channel",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
                {"Free channel",   0, menuCallback, (void*) Menu::FREE_CHANNEL},
                {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
@@ -290,21 +327,21 @@ void geSampleChannel::__cb_openMenu()
                rclick_menu[(int) Menu::CLEAR_ACTIONS].deactivate();
 
        /* No 'clear start/stop actions' for those channels in loop mode: they cannot
-  have start/stop actions. */
+       have start/stop actions. */
 
        if (static_cast<SampleChannel*>(ch)->mode & LOOP_ANY)
                rclick_menu[(int) Menu::CLEAR_ACTIONS_START_STOP].deactivate();
 
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       Fl_Menu_Buttonb = new Fl_Menu_Button(0, 0, 100, 50);
        b->box(G_CUSTOM_BORDER_BOX);
        b->textsize(G_GUI_FONT_SIZE_BASE);
        b->textcolor(G_COLOR_LIGHT_2);
        b->color(G_COLOR_GREY_2);
 
-       const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-  if (m)
-    m->do_callback(this, m->user_data());
-  return;
+       const Fl_Menu_Itemm = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       if (m)
+               m->do_callback(this, m->user_data());
+       return;
 }
 
 
@@ -313,7 +350,7 @@ void geSampleChannel::__cb_openMenu()
 
 void geSampleChannel::__cb_readActions()
 {
-       glue_startStopReadingRecs((SampleChannel*) ch);
+       glue_startStopReadingRecs(static_cast<SampleChannel*>(ch));
 }
 
 
@@ -322,12 +359,12 @@ void geSampleChannel::__cb_readActions()
 
 void geSampleChannel::refresh()
 {
-  if (!mainButton->visible()) // mainButton invisible? status too (see below)
-    return;
+       if (!mainButton->visible()) // mainButton invisible? status too (see below)
+               return;
 
        setColorsByStatus(ch->status, ch->recStatus);
 
-       if (((SampleChannel*) ch)->wave != nullptr) {
+       if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
                if (mixer::recording && ch->armed)
                        mainButton->setInputRecordMode();
                if (recorder::active) {
@@ -347,7 +384,7 @@ void geSampleChannel::reset()
 {
        hideActionButton();
        mainButton->setDefaultMode("-- no sample --");
-       mainButton->redraw();
+       mainButton->redraw();
        status->redraw();
 }
 
@@ -368,7 +405,7 @@ void geSampleChannel::update()
                        mainButton->label("* file not found! *");
                        break;
                default:
-                       mainButton->label(((SampleChannel*) ch)->wave->getName().c_str());
+                       mainButton->label(static_cast<SampleChannel*>(ch)->wave->getName().c_str());
                        break;
        }
 
@@ -383,7 +420,7 @@ void geSampleChannel::update()
 
        /* updates modebox */
 
-       modeBox->value(((SampleChannel*) ch)->mode);
+       modeBox->value(static_cast<SampleChannel*>(ch)->mode);
        modeBox->redraw();
 
        /* update volumes+mute+solo */
@@ -406,7 +443,7 @@ void geSampleChannel::update()
 
 void geSampleChannel::showActionButton()
 {
-       readActions->value(((SampleChannel*) ch)->readActions);
+       readActions->value(static_cast<SampleChannel*>(ch)->readActions);
        readActions->show();
        packWidgets();
        redraw();
@@ -429,7 +466,7 @@ void geSampleChannel::hideActionButton()
 
 void geSampleChannel::resize(int X, int Y, int W, int H)
 {
-  geChannel::resize(X, Y, W, H);
+       geChannel::resize(X, Y, W, H);
 
        arm->hide();
        modeBox->hide();
@@ -451,3 +488,15 @@ void geSampleChannel::resize(int X, int Y, int W, int H)
 
        packWidgets();
 }
+
+
+void geSampleChannel::changeSize(int H)
+{
+       geChannel::changeSize(H);
+
+       int Y = y() + (H / 2 - (G_GUI_UNIT / 2));
+
+       status->resize(x(), Y, w(), G_GUI_UNIT);
+       modeBox->resize(x(), Y, w(), G_GUI_UNIT);
+       readActions->resize(x(), Y, w(), G_GUI_UNIT);
+}
\ No newline at end of file
index 875682d45a7aee496cc423bdf1b982efa67b3e1d..0e070bc120a79aedb94500a302ef60c635c6db65 100644 (file)
@@ -41,22 +41,24 @@ class geSampleChannel : public geChannel
 {
 private:
 
-       static void cb_button        (Fl_Widget *v, void *p);
-       static void cb_openMenu      (Fl_Widget *v, void *p);
-       static void cb_readActions   (Fl_Widget *v, void *p);
-
-       inline void __cb_button      ();
-       inline void __cb_openMenu    ();
-       inline void __cb_readActions ();
+       static void cb_button     (Fl_Widget* v, void* p);
+       static void cb_openMenu   (Fl_Widget* v, void* p);
+       static void cb_readActions(Fl_Widget* v, void* p);
+       void __cb_button     ();
+       void __cb_openMenu   ();
+       void __cb_readActions();
 
 public:
 
-       geSampleChannel(int x, int y, int w, int h, SampleChannel *ch);
+       geSampleChannel(int x, int y, int w, int h, SampleChannel* ch);
+
+       void resize(int x, int y, int w, int h) override;
+
+       void reset() override;
+       void update() override;
+       void refresh() override;
 
-       void reset   ();
-       void update  ();
-       void refresh ();
-       void resize  (int x, int y, int w, int h);
+       void changeSize(int h);
 
        /* show/hideActionButton
        Adds or removes 'R' button when actions are available. */
@@ -64,8 +66,8 @@ public:
        void showActionButton();
        void hideActionButton();
 
-       geChannelMode *modeBox;
-       geButton            *readActions;
+       geChannelModemodeBox;
+       geButton*      readActions;
 };
 
 
index 66f886786ca84263ef8559dbc2dcf489de635c7a..a2a9c3ff2938639a7f347c38d12ecefa4e860b19 100644 (file)
@@ -41,7 +41,7 @@ extern gdMainWindow *G_MainWin;
 
 
 geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h,
-  const char *l)
+       const char *l)
        : geChannelButton(x, y, w, h, l)
 {
 }
@@ -61,9 +61,9 @@ int geSampleChannelButton::handle(int e)
                        break;
                }
                case FL_PASTE: {
-      geSampleChannel *gch = static_cast<geSampleChannel*>(parent());
-      SampleChannel   *ch  = static_cast<SampleChannel*>(gch->ch);
-      int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str());
+                       geSampleChannel *gch = static_cast<geSampleChannel*>(parent());
+                       SampleChannel   *ch  = static_cast<SampleChannel*>(gch->ch);
+                       int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str());
                        if (result != G_RES_OK)
                                G_MainWin->keyboard->printChannelMessage(result);
                        ret = 1;
index 84da01e7f2fcf4c75a525b1a67122b8ac2aee289..80e231968faa0b73851a571f9d8091f192f95106 100644 (file)
@@ -43,7 +43,7 @@
 using namespace giada::m;
 
 
-gePitchTool::gePitchTool(int x, int y, SampleChannel *ch)
+gePitchTool::gePitchTool(int x, int y, SampleChannelch)
   : Fl_Group(x, y, 600, 20),
     ch      (ch)
 {
@@ -91,13 +91,13 @@ void gePitchTool::refresh()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::cb_setPitch      (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitch(); }
-void gePitchTool::cb_setPitchToBar (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchToBar(); }
-void gePitchTool::cb_setPitchToSong(Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchToSong(); }
-void gePitchTool::cb_setPitchHalf  (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchHalf(); }
-void gePitchTool::cb_setPitchDouble(Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchDouble(); }
-void gePitchTool::cb_resetPitch    (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_resetPitch(); }
-void gePitchTool::cb_setPitchNum   (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchNum(); }
+void gePitchTool::cb_setPitch      (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitch(); }
+void gePitchTool::cb_setPitchToBar (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToBar(); }
+void gePitchTool::cb_setPitchToSong(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToSong(); }
+void gePitchTool::cb_setPitchHalf  (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchHalf(); }
+void gePitchTool::cb_setPitchDouble(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchDouble(); }
+void gePitchTool::cb_resetPitch    (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_resetPitch(); }
+void gePitchTool::cb_setPitchNum   (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchNum(); }
 
 
 /* -------------------------------------------------------------------------- */
@@ -141,7 +141,8 @@ void gePitchTool::__cb_setPitchDouble()
 
 void gePitchTool::__cb_setPitchToBar()
 {
-  glue_setPitch(ch, ch->getEnd() / (float) clock::getFramesPerBar());
+  // TODO - opaque channel's count
+  glue_setPitch(ch, (ch->getEnd()*2) / (float) clock::getFramesPerBar());
 }
 
 
@@ -150,7 +151,8 @@ void gePitchTool::__cb_setPitchToBar()
 
 void gePitchTool::__cb_setPitchToSong()
 {
-  glue_setPitch(ch, ch->getEnd() / (float) clock::getTotalFrames());
+  // TODO - opaque channel's count
+  glue_setPitch(ch, (ch->getEnd()*2) / (float) clock::getTotalFrames());
 }
 
 
index 8abd173fc86e350fa90a1725f114759e9dc2ff00..9bdd59a37d24b477ea1a7e7096a782e30a9b279e 100644 (file)
@@ -90,7 +90,7 @@ void geRangeTool::cb_resetStartEnd(Fl_Widget* w, void* p) { ((geRangeTool*)p)->_
 
 void geRangeTool::__cb_setChanPos()
 {
-  sampleEditor::setBeginEndChannel(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
+  sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
   static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
 }
 
@@ -100,6 +100,6 @@ void geRangeTool::__cb_setChanPos()
 
 void geRangeTool::__cb_resetStartEnd()
 {
-  sampleEditor::setBeginEndChannel(m_ch, 0, m_ch->wave->getSize() - 1);
+  sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
   static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
 }
index 0b7e059c81d3363a31b7a5802623cd1a2ddd3311..7bfdb183af69c065706205ea549e295d6c3fafec 100644 (file)
@@ -48,13 +48,18 @@ namespace
 {
 enum class Menu
 {
-  CUT = 0,
-  TRIM,
-  SILENCE,
-  FADE_IN,
-  FADE_OUT,
-  SMOOTH_EDGES,
-  SET_START_END
+       CUT = 0,
+       COPY,
+       PASTE,
+       TRIM,
+       SILENCE,
+       REVERSE,
+       NORMALIZE,
+       FADE_IN,
+       FADE_OUT,
+       SMOOTH_EDGES,
+       SET_BEGIN_END,
+       TO_NEW_CHANNEL
 };
 
 
@@ -63,35 +68,50 @@ enum class Menu
 
 void menuCallback(Fl_Widget* w, void* v)
 {
-  geWaveTools* wavetools = static_cast<geWaveTools*>(w);
-  Menu selectedItem = (Menu) (intptr_t) v;
-
-  int a = wavetools->waveform->getSelectionA();
-  int b = wavetools->waveform->getSelectionB();
-
-  switch (selectedItem) {
-       case Menu::CUT:
-      c::sampleEditor::cut(wavetools->ch, a, b);
-               break;
-       case Menu::TRIM:
-      c::sampleEditor::trim(wavetools->ch, a, b);
-               break;
-       case Menu::SILENCE:
-               c::sampleEditor::silence(wavetools->ch, a, b);
-               break;  
-       case Menu::FADE_IN:
-               c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_IN);
-               break;
-       case Menu::FADE_OUT:
-               c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_OUT);
-               break;
-       case Menu::SMOOTH_EDGES:
-               c::sampleEditor::smoothEdges(wavetools->ch, a, b);
-               break;
-       case Menu::SET_START_END:
-               c::sampleEditor::setStartEnd(wavetools->ch, a, b);
-               break;
-  }
+       geWaveTools* wavetools = static_cast<geWaveTools*>(w);
+       Menu selectedItem = (Menu) (intptr_t) v;
+
+       int a = wavetools->waveform->getSelectionA();
+       int b = wavetools->waveform->getSelectionB();
+
+       switch (selectedItem) {
+               case Menu::CUT:
+                       c::sampleEditor::cut(wavetools->ch, a, b);
+                       break;          
+               case Menu::COPY:
+                       c::sampleEditor::copy(wavetools->ch, a, b);
+                       break;          
+               case Menu::PASTE:
+                       c::sampleEditor::paste(wavetools->ch, a);
+                       break;
+               case Menu::TRIM:
+                       c::sampleEditor::trim(wavetools->ch, a, b);
+                       break;
+               case Menu::SILENCE:
+                       c::sampleEditor::silence(wavetools->ch, a, b);
+                       break;    
+               case Menu::REVERSE:
+                       c::sampleEditor::reverse(wavetools->ch, a, b);
+                       break;                  
+               case Menu::NORMALIZE:
+                       c::sampleEditor::normalizeHard(wavetools->ch, a, b);
+                       break;  
+               case Menu::FADE_IN:
+                       c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_IN);
+                       break;
+               case Menu::FADE_OUT:
+                       c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_OUT);
+                       break;
+               case Menu::SMOOTH_EDGES:
+                       c::sampleEditor::smoothEdges(wavetools->ch, a, b);
+                       break;
+               case Menu::SET_BEGIN_END:
+                       c::sampleEditor::setBeginEnd(wavetools->ch, a, b);
+                       break;          
+               case Menu::TO_NEW_CHANNEL:
+                       c::sampleEditor::toNewChannel(wavetools->ch, a, b);
+                       break;
+       }
 }
 }; // {anonymous}
 
@@ -101,7 +121,7 @@ void menuCallback(Fl_Widget* w, void* v)
 
 geWaveTools::geWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l)
        : Fl_Scroll(x, y, w, h, l),
-         ch       (ch)
+               ch       (ch)
 {
        type(Fl_Scroll::HORIZONTAL_ALWAYS);
        hscrollbar.color(G_COLOR_GREY_2);
@@ -185,25 +205,40 @@ int geWaveTools::handle(int e)
 
 void geWaveTools::openMenu()
 {
-       if (!waveform->isSelected())
-               return;
-
        Fl_Menu_Item menu[] = {
-               {"Cut",                0, menuCallback, (void*) Menu::CUT},
-    {"Trim",               0, menuCallback, (void*) Menu::TRIM},
-    {"Silence",            0, menuCallback, (void*) Menu::SILENCE},
-    {"Fade in",            0, menuCallback, (void*) Menu::FADE_IN},
-    {"Fade out",           0, menuCallback, (void*) Menu::FADE_OUT},
-    {"Smooth edges",       0, menuCallback, (void*) Menu::SMOOTH_EDGES},
-    {"Set start/end here", 0, menuCallback, (void*) Menu::SET_START_END},
-    {0}
+               {"Cut",                 0, menuCallback, (void*) Menu::CUT},
+               {"Copy",                0, menuCallback, (void*) Menu::COPY},
+               {"Paste",               0, menuCallback, (void*) Menu::PASTE},
+               {"Trim",                0, menuCallback, (void*) Menu::TRIM},
+               {"Silence",             0, menuCallback, (void*) Menu::SILENCE},
+               {"Reverse",             0, menuCallback, (void*) Menu::REVERSE},
+               {"Normalize",           0, menuCallback, (void*) Menu::NORMALIZE},
+               {"Fade in",             0, menuCallback, (void*) Menu::FADE_IN},
+               {"Fade out",            0, menuCallback, (void*) Menu::FADE_OUT},
+               {"Smooth edges",        0, menuCallback, (void*) Menu::SMOOTH_EDGES},
+               {"Set begin/end here",  0, menuCallback, (void*) Menu::SET_BEGIN_END},
+               {"Copy to new channel", 0, menuCallback, (void*) Menu::TO_NEW_CHANNEL},
+               {0}
        };
 
-  if (ch->status == STATUS_PLAY) {
-    menu[(int)Menu::CUT].deactivate();
-    menu[(int)Menu::TRIM].deactivate();
-  }
+       if (ch->status == STATUS_PLAY) {
+               menu[(int)Menu::CUT].deactivate();
+               menu[(int)Menu::TRIM].deactivate();
+       }
 
+       if (!waveform->isSelected()) {
+               menu[(int)Menu::CUT].deactivate();
+               menu[(int)Menu::COPY].deactivate();             
+               menu[(int)Menu::TRIM].deactivate();             
+               menu[(int)Menu::SILENCE].deactivate();          
+               menu[(int)Menu::REVERSE].deactivate();          
+               menu[(int)Menu::NORMALIZE].deactivate();                
+               menu[(int)Menu::FADE_IN].deactivate();          
+               menu[(int)Menu::FADE_OUT].deactivate();         
+               menu[(int)Menu::SMOOTH_EDGES].deactivate();             
+               menu[(int)Menu::SET_BEGIN_END].deactivate();            
+               menu[(int)Menu::TO_NEW_CHANNEL].deactivate();           
+       }
 
        Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
        b->box(G_CUSTOM_BORDER_BOX);
@@ -212,7 +247,7 @@ void geWaveTools::openMenu()
        b->color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
-  if (m)
-    m->do_callback(this, m->user_data());
-  return;
+       if (m)
+               m->do_callback(this, m->user_data());
+       return;
 }
index d153ad18bd0f83cf345e20df0f9cbe9ebc998f83..d13b369792d9e97a3cdca5b57fdb872c064f3f70 100644 (file)
@@ -50,26 +50,26 @@ using namespace giada::c;
 
 geWaveform::geWaveform(int x, int y, int w, int h, SampleChannel* ch, const char* l)
 : Fl_Widget     (x, y, w, h, l),
-  m_selection   {},
-  m_ch          (ch),
-  m_chanStart   (0),
-  m_chanStartLit(false),
-  m_chanEnd     (0),
-  m_chanEndLit  (false),
-  m_pushed      (false),
-  m_dragged     (false),
-  m_resizedA    (false),
-  m_resizedB    (false),
-  m_ratio       (0.0f)
+       m_selection   {},
+       m_ch          (ch),
+       m_chanStart   (0),
+       m_chanStartLit(false),
+       m_chanEnd     (0),
+       m_chanEndLit  (false),
+       m_pushed      (false),
+       m_dragged     (false),
+       m_resizedA    (false),
+       m_resizedB    (false),
+       m_ratio       (0.0f)
 {
-  m_data.sup  = nullptr;
-  m_data.inf  = nullptr;
-  m_data.size = 0;
+       m_data.sup  = nullptr;
+       m_data.inf  = nullptr;
+       m_data.size = 0;
 
-  m_grid.snap  = conf::sampleEditorGridOn;
-  m_grid.level = conf::sampleEditorGridVal;
+       m_grid.snap  = conf::sampleEditorGridOn;
+       m_grid.level = conf::sampleEditorGridVal;
 
-  alloc(w);
+       alloc(w);
 }
 
 
@@ -78,7 +78,7 @@ geWaveform::geWaveform(int x, int y, int w, int h, SampleChannel* ch, const char
 
 geWaveform::~geWaveform()
 {
-  freeData();
+       freeData();
 }
 
 
@@ -87,14 +87,14 @@ geWaveform::~geWaveform()
 
 void geWaveform::freeData()
 {
-  if (m_data.sup) {
-    delete[] m_data.sup;
-    delete[] m_data.inf;
-    m_data.sup  = nullptr;
-    m_data.inf  = nullptr;
-    m_data.size = 0;
-  }
-  m_grid.points.clear();
+       if (m_data.sup) {
+               delete[] m_data.sup;
+               delete[] m_data.inf;
+               m_data.sup  = nullptr;
+               m_data.inf  = nullptr;
+               m_data.size = 0;
+       }
+       m_grid.points.clear();
 }
 
 
@@ -103,60 +103,60 @@ void geWaveform::freeData()
 
 int geWaveform::alloc(int datasize, bool force)
 {
-  Wave* wave = m_ch->wave;
+       Wave* wave = m_ch->wave;
 
-  m_ratio = wave->getSize() / (float) datasize;
+       m_ratio = wave->getSize() / (float) datasize;
 
-  /* Limit 1:1 drawing (to avoid sub-frame drawing) by keeping m_ratio >= 1. */
+       /* Limit 1:1 drawing (to avoid sub-frame drawing) by keeping m_ratio >= 1. */
 
-  if (m_ratio < 1) {  
-    datasize = wave->getSize();
-    m_ratio = 1;
-  }
+       if (m_ratio < 1) {  
+               datasize = wave->getSize();
+               m_ratio = 1;
+       }
 
-  if (datasize == m_data.size && !force)
-       return 0;
+       if (datasize == m_data.size && !force)
+               return 0;
 
-  freeData();
+       freeData();
 
-  m_data.size = datasize;
-  m_data.sup  = new (std::nothrow) int[m_data.size];
-  m_data.inf  = new (std::nothrow) int[m_data.size];
+       m_data.size = datasize;
+       m_data.sup  = new (std::nothrow) int[m_data.size];
+       m_data.inf  = new (std::nothrow) int[m_data.size];
 
-  if (!m_data.sup || !m_data.inf) {
-       gu_log("[geWaveform::alloc] unable to allocate memory for the waveform!\n");
-    return 0;
-  }
+       if (!m_data.sup || !m_data.inf) {
+               gu_log("[geWaveform::alloc] unable to allocate memory for the waveform!\n");
+               return 0;
+       }
 
-  gu_log("[geWaveform::alloc] %d pixels, %f m_ratio\n", m_data.size, m_ratio);
+       gu_log("[geWaveform::alloc] %d pixels, %f m_ratio\n", m_data.size, m_ratio);
 
-  int offset = h() / 2;
-  int zero   = y() + offset; // center, zero amplitude (-inf dB)
+       int offset = h() / 2;
+       int zero   = y() + offset; // center, zero amplitude (-inf dB)
 
-  /* Frid frequency: store a grid point every 'gridFreq' frame (if grid is
-  enabled). TODO - this will cause round off errors, since gridFreq is integer. */
+       /* Frid frequency: store a grid point every 'gridFreq' frame (if grid is
+       enabled). TODO - this will cause round off errors, since gridFreq is integer. */
 
-  int gridFreq = m_grid.level != 0 ? wave->getSize() / m_grid.level : 0;
+       int gridFreq = m_grid.level != 0 ? wave->getSize() / m_grid.level : 0;
 
        /* Resampling the waveform, hardcore way. Many thanks to 
        http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html */
 
-  for (int i=0; i<m_data.size; i++) {
-    
-    /* Scan the original waveform in chunks [pc, pn]. */
+       for (int i=0; i<m_data.size; i++) {
+               
+               /* Scan the original waveform in chunks [pc, pn]. */
 
-    float pc = i     * m_ratio;  // current point
-    float pn = (i+1) * m_ratio;  // next point
+               int pc = i     * m_ratio;  // current point TODO - int until we switch to uint32_t for Wave size...
+               int pn = (i+1) * m_ratio;  // next point    TODO - int until we switch to uint32_t for Wave size...
 
-    float peaksup = 0.0f;
-    float peakinf = 0.0f;
+               float peaksup = 0.0f;
+               float peakinf = 0.0f;
 
-    for (float k=pc; k<pn; k++) {
+               for (int k=pc; k<pn; k++) { // TODO - int until we switch to uint32_t for Wave size...
 
-       if (k >= wave->getSize())
-               continue;
+                       if (k >= wave->getSize())
+                               continue;
 
-      /* Compute average of stereo signal. */
+                       /* Compute average of stereo signal. */
 
                        float avg = 0.0f;
                        float* frame = wave->getFrame(k);
@@ -173,19 +173,19 @@ int geWaveform::alloc(int datasize, bool force)
 
                        if (gridFreq != 0 && (int) k % gridFreq == 0 && k != 0)
                                m_grid.points.push_back(k);
-    }
+               }
 
-    m_data.sup[i] = zero - (peaksup * m_ch->getBoost() * offset);
-    m_data.inf[i] = zero - (peakinf * m_ch->getBoost() * offset);
+               m_data.sup[i] = zero - (peaksup * m_ch->getBoost() * offset);
+               m_data.inf[i] = zero - (peakinf * m_ch->getBoost() * offset);
 
-    // avoid window overflow
+               // avoid window overflow
 
-    if (m_data.sup[i] < y())       m_data.sup[i] = y();
-    if (m_data.inf[i] > y()+h()-1) m_data.inf[i] = y()+h()-1;
-  }
+               if (m_data.sup[i] < y())       m_data.sup[i] = y();
+               if (m_data.inf[i] > y()+h()-1) m_data.inf[i] = y()+h()-1;
+       }
 
-  recalcPoints();
-  return 1;
+       recalcPoints();
+       return 1;
 }
 
 
@@ -194,8 +194,8 @@ int geWaveform::alloc(int datasize, bool force)
 
 void geWaveform::recalcPoints()
 {
-  m_chanStart = m_ch->getBegin();
-  m_chanEnd   = m_ch->getEnd();
+       m_chanStart = m_ch->getBegin();
+       m_chanEnd   = m_ch->getEnd();
 }
 
 
@@ -204,21 +204,21 @@ void geWaveform::recalcPoints()
 
 void geWaveform::drawSelection()
 {
-  if (!isSelected()) 
-    return;
+       if (!isSelected()) 
+               return;
 
-  int a = frameToPixel(m_selection.a) + x();
-  int b = frameToPixel(m_selection.b) + x();
+       int a = frameToPixel(m_selection.a) + x();
+       int b = frameToPixel(m_selection.b) + x();
 
-  if (a < 0)
-    a = 0;
-  if (b >= w() + BORDER)
-    b = w() + BORDER;
+       if (a < 0)
+               a = 0;
+       if (b >= w() + BORDER)
+               b = w() + BORDER;
 
-  if (a < b)
-    fl_rectf(a, y(), b-a, h(), G_COLOR_GREY_4);
-  else
-    fl_rectf(b, y(), a-b, h(), G_COLOR_GREY_4);
+       if (a < b)
+               fl_rectf(a, y(), b-a, h(), G_COLOR_GREY_4);
+       else
+               fl_rectf(b, y(), a-b, h(), G_COLOR_GREY_4);
 }
 
 
@@ -227,15 +227,15 @@ void geWaveform::drawSelection()
 
 void geWaveform::drawWaveform(int from, int to)
 {
-  int zero = y() + (h() / 2); // zero amplitude (-inf dB)
-
-  fl_color(G_COLOR_BLACK);
-  for (int i=from; i<to; i++) {
-       if (i >= m_data.size)
-               break;
-    fl_line(i+x(), zero, i+x(), m_data.sup[i]);
-    fl_line(i+x(), zero, i+x(), m_data.inf[i]);
-  }
+       int zero = y() + (h() / 2); // zero amplitude (-inf dB)
+
+       fl_color(G_COLOR_BLACK);
+       for (int i=from; i<to; i++) {
+               if (i >= m_data.size)
+                       break;
+               fl_line(i+x(), zero, i+x(), m_data.sup[i]);
+               fl_line(i+x(), zero, i+x(), m_data.inf[i]);
+       }
 }
 
 
@@ -262,38 +262,38 @@ void geWaveform::drawGrid(int from, int to)
 
 void geWaveform::drawStartEndPoints()
 {
-  /* print m_chanStart */
+       /* print m_chanStart */
 
-  int lineX = frameToPixel(m_chanStart) + x();
+       int lineX = frameToPixel(m_chanStart) + x();
 
-  if (m_chanStartLit) fl_color(G_COLOR_LIGHT_2);
-  else              fl_color(G_COLOR_LIGHT_1);
+       if (m_chanStartLit) fl_color(G_COLOR_LIGHT_2);
+       else              fl_color(G_COLOR_LIGHT_1);
 
-  /* vertical line */
+       /* vertical line */
 
-  fl_line(lineX, y()+1, lineX, y()+h()-2);
+       fl_line(lineX, y()+1, lineX, y()+h()-2);
 
-  /* print flag and avoid overflow */
+       /* print flag and avoid overflow */
 
-  if (lineX+FLAG_WIDTH > w()+x()-2)
-    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
-  else
-    fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
+       if (lineX+FLAG_WIDTH > w()+x()-2)
+               fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
+       else
+               fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
 
-  /* print m_chanEnd */
+       /* print m_chanEnd */
 
-  lineX = frameToPixel(m_chanEnd) + x() - 1;
-  if (m_chanEndLit) fl_color(G_COLOR_LIGHT_2);
-  else            fl_color(G_COLOR_LIGHT_1);
+       lineX = frameToPixel(m_chanEnd) + x() - 1;
+       if (m_chanEndLit) fl_color(G_COLOR_LIGHT_2);
+       else            fl_color(G_COLOR_LIGHT_1);
 
-  /* vertical line */
+       /* vertical line */
 
-  fl_line(lineX, y()+1, lineX, y()+h()-2);
+       fl_line(lineX, y()+1, lineX, y()+h()-2);
 
-  if (lineX-FLAG_WIDTH < x())
-    fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
-  else
-    fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
+       if (lineX-FLAG_WIDTH < x())
+               fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
+       else
+               fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
 }
 
 
@@ -302,9 +302,9 @@ void geWaveform::drawStartEndPoints()
 
 void geWaveform::drawPlayHead()
 {
-  int p = frameToPixel(m_ch->getTrackerPreview()) + x();
-  fl_color(G_COLOR_LIGHT_2);
-  fl_line(p, y() + 1, p, y() + h() - 2);
+       int p = frameToPixel(m_ch->getTrackerPreview()) + x();
+       fl_color(G_COLOR_LIGHT_2);
+       fl_line(p, y() + 1, p, y() + h() - 2);
 }
 
 
@@ -313,27 +313,27 @@ void geWaveform::drawPlayHead()
 
 void geWaveform::draw()
 {
-  assert(m_data.sup != nullptr);
-  assert(m_data.inf != nullptr);
+       assert(m_data.sup != nullptr);
+       assert(m_data.inf != nullptr);
 
-  fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2);  // blank canvas
+       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2);  // blank canvas
 
-  /* Draw things from 'from' (offset driven by the scrollbar) to 'to' (width of 
-  parent window). We don't draw the entire waveform, only the visibile part. */
+       /* Draw things from 'from' (offset driven by the scrollbar) to 'to' (width of 
+       parent window). We don't draw the entire waveform, only the visibile part. */
 
-  int from = abs(x() - parent()->x());
-  int to = from + parent()->w();
-  if (x() + w() < parent()->w())
-    to = x() + w() - BORDER;
+       int from = abs(x() - parent()->x());
+       int to = from + parent()->w();
+       if (x() + w() < parent()->w())
+               to = x() + w() - BORDER;
 
-  drawSelection();
-  drawWaveform(from, to);
-  drawGrid(from, to);
-  drawPlayHead();
+       drawSelection();
+       drawWaveform(from, to);
+       drawGrid(from, to);
+       drawPlayHead();
 
-  fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);   // border box
-  
-  drawStartEndPoints();
+       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);   // border box
+       
+       drawStartEndPoints();
 }
 
 
@@ -345,161 +345,166 @@ int geWaveform::handle(int e)
        m_mouseX = pixelToFrame(Fl::event_x() - x());
        m_mouseY = pixelToFrame(Fl::event_y() - y());
 
-  switch (e) {
+       switch (e) {
 
-    case FL_KEYDOWN: {
-      if (Fl::event_key() == ' ')
-        static_cast<gdSampleEditor*>(window())->__cb_togglePreview();
-      else
-      if (Fl::event_key() == FL_BackSpace)
+               case FL_KEYDOWN: {
+                       if (Fl::event_key() == ' ')
+                               static_cast<gdSampleEditor*>(window())->__cb_togglePreview();
+                       else
+                       if (Fl::event_key() == FL_BackSpace)
                                sampleEditor::rewindPreview(m_ch);
-      return 1;
-    }
-
-    case FL_PUSH: {
-
-      m_pushed = true;
-
-      if (!mouseOnEnd() && !mouseOnStart()) {
-        if (Fl::event_button3())  // let the parent (waveTools) handle this
-          return 0;
-        if (mouseOnSelectionA())
-          m_resizedA = true;
-        else
-        if(mouseOnSelectionB())
-          m_resizedB = true;
-        else {
-          m_dragged = true;
-          m_selection.a = m_mouseX;
-          m_selection.b = m_mouseX;
-        }
-      }
-      return 1;
-    }
-
-    case FL_RELEASE: {
-
-       sampleEditor::setPlayHead(m_ch, m_mouseX);
-
-      /* If selection has been done (m_dragged or resized), make sure that point A 
-      is always lower than B. */
-
-      if (m_dragged || m_resizedA || m_resizedB)
-        fixSelection();
-
-      /* Handle begin/end markers interaction. */
-
-      if (m_chanStartLit || m_chanEndLit)
-        sampleEditor::setBeginEndChannel(m_ch, m_chanStart, m_chanEnd);
-
-      m_pushed   = false;
-      m_dragged  = false;
-      m_resizedA = false;
-      m_resizedB = false;
-
-      redraw();
-      return 1;
-    }
-
-    case FL_ENTER: {  // enables FL_DRAG
-      return 1;
-    }
-
-    case FL_LEAVE: {
-      if (m_chanStartLit || m_chanEndLit) {
-        m_chanStartLit = false;
-        m_chanEndLit   = false;
-        redraw();
-      }
-      return 1;
-    }
-
-    case FL_MOVE: {
-
-      if (mouseOnStart()) {
-        m_chanStartLit = true;
-        redraw();
-      }
-      else
-      if (m_chanStartLit) {
-        m_chanStartLit = false;
-        redraw();
-      }
-
-      if (mouseOnEnd()) {
-        m_chanEndLit = true;
-        redraw();
-      }
-      else
-      if (m_chanEndLit) {
-        m_chanEndLit = false;
-        redraw();
-      }
-
-      if (mouseOnSelectionA() && isSelected())
-        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-      else
-      if (mouseOnSelectionB() && isSelected())
-        fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-      else
-        fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-
-      return 1;
-    }
-
-    case FL_DRAG: {
-
-      /* here the mouse is on the m_chanStart tool */
-
-      if (m_chanStartLit && m_pushed) {
-
-        m_chanStart = snap(m_mouseX);
-
-        if (m_chanStart < 0)
-          m_chanStart = 0;
-        else
-        if (m_chanStart >= m_chanEnd)
-          m_chanStart = m_chanEnd - 2;
-
-        redraw();
-      }
-      else
-      if (m_chanEndLit && m_pushed) {
-
-        m_chanEnd = snap(m_mouseX);
-
-        if (m_chanEnd > m_ch->wave->getSize())
-          m_chanEnd = m_ch->wave->getSize();
-        else
-        if (m_chanEnd <= m_chanStart)
-          m_chanEnd = m_chanStart + 2;
-
-        redraw();
-      }
-
-      /* Here the mouse is on the waveform, i.e. a new selection has started. */
-
-      else
-      if (m_dragged) {
-        m_selection.b = snap(m_mouseX);
-        redraw();
-      }
-
-      /* here the mouse is on a selection boundary i.e. resize */
-
-      else
-      if (m_resizedA || m_resizedB) {
-        int pos = snap(m_mouseX);
-        m_resizedA ? m_selection.a = pos : m_selection.b = pos;
-        redraw();
-      }
-
-      return 1;
-    }
-
-    default:
-      return Fl_Widget::handle(e);
-  }
+                       return 1;
+               }
+
+               case FL_PUSH: {
+
+                       if (Fl::event_clicks() > 0) {
+                               selectAll();
+                               return 1;
+                       }
+
+                       m_pushed = true;
+
+                       if (!mouseOnEnd() && !mouseOnStart()) {
+                               if (Fl::event_button3())  // let the parent (waveTools) handle this
+                                       return 0;
+                               if (mouseOnSelectionA())
+                                       m_resizedA = true;
+                               else
+                               if(mouseOnSelectionB())
+                                       m_resizedB = true;
+                               else {
+                                       m_dragged = true;
+                                       m_selection.a = m_mouseX;
+                                       m_selection.b = m_mouseX;
+                               }
+                       }
+                       return 1;
+               }
+
+               case FL_RELEASE: {
+
+                       sampleEditor::setPlayHead(m_ch, m_mouseX);
+
+                       /* If selection has been done (m_dragged or resized), make sure that point A 
+                       is always lower than B. */
+
+                       if (m_dragged || m_resizedA || m_resizedB)
+                               fixSelection();
+
+                       /* Handle begin/end markers interaction. */
+
+                       if (m_chanStartLit || m_chanEndLit)
+                               sampleEditor::setBeginEnd(m_ch, m_chanStart, m_chanEnd);
+
+                       m_pushed   = false;
+                       m_dragged  = false;
+                       m_resizedA = false;
+                       m_resizedB = false;
+
+                       redraw();
+                       return 1;
+               }
+
+               case FL_ENTER: {  // enables FL_DRAG
+                       return 1;
+               }
+
+               case FL_LEAVE: {
+                       if (m_chanStartLit || m_chanEndLit) {
+                               m_chanStartLit = false;
+                               m_chanEndLit   = false;
+                               redraw();
+                       }
+                       return 1;
+               }
+
+               case FL_MOVE: {
+
+                       if (mouseOnStart()) {
+                               m_chanStartLit = true;
+                               redraw();
+                       }
+                       else
+                       if (m_chanStartLit) {
+                               m_chanStartLit = false;
+                               redraw();
+                       }
+
+                       if (mouseOnEnd()) {
+                               m_chanEndLit = true;
+                               redraw();
+                       }
+                       else
+                       if (m_chanEndLit) {
+                               m_chanEndLit = false;
+                               redraw();
+                       }
+
+                       if (mouseOnSelectionA() && isSelected())
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       else
+                       if (mouseOnSelectionB() && isSelected())
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       else
+                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+
+                       return 1;
+               }
+
+               case FL_DRAG: {
+
+                       /* here the mouse is on the m_chanStart tool */
+
+                       if (m_chanStartLit && m_pushed) {
+
+                               m_chanStart = snap(m_mouseX);
+
+                               if (m_chanStart < 0)
+                                       m_chanStart = 0;
+                               else
+                               if (m_chanStart >= m_chanEnd)
+                                       m_chanStart = m_chanEnd - 2;
+
+                               redraw();
+                       }
+                       else
+                       if (m_chanEndLit && m_pushed) {
+
+                               m_chanEnd = snap(m_mouseX);
+
+                               if (m_chanEnd > m_ch->wave->getSize())
+                                       m_chanEnd = m_ch->wave->getSize();
+                               else
+                               if (m_chanEnd <= m_chanStart)
+                                       m_chanEnd = m_chanStart + 2;
+
+                               redraw();
+                       }
+
+                       /* Here the mouse is on the waveform, i.e. a new selection has started. */
+
+                       else
+                       if (m_dragged) {
+                               m_selection.b = snap(m_mouseX);
+                               redraw();
+                       }
+
+                       /* here the mouse is on a selection boundary i.e. resize */
+
+                       else
+                       if (m_resizedA || m_resizedB) {
+                               int pos = snap(m_mouseX);
+                               m_resizedA ? m_selection.a = pos : m_selection.b = pos;
+                               redraw();
+                       }
+
+                       return 1;
+               }
+
+               default:
+                       return Fl_Widget::handle(e);
+       }
 }
 
 
@@ -512,7 +517,7 @@ int geWaveform::snap(int pos)
                return pos;
        for (int pf : m_grid.points) {
                if (pos >= pf - pixelToFrame(SNAPPING) &&
-                   pos <= pf + pixelToFrame(SNAPPING))
+                               pos <= pf + pixelToFrame(SNAPPING))
                {
                        return pf;
                }
@@ -529,9 +534,9 @@ bool geWaveform::mouseOnStart()
        int mouseXp    = frameToPixel(m_mouseX);
        int mouseYp    = frameToPixel(m_mouseY);
        int chanStartP = frameToPixel(m_chanStart);
-  return mouseXp - (FLAG_WIDTH / 2) >  chanStartP - BORDER              &&
-         mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
-         mouseYp > h() - FLAG_HEIGHT;
+       return mouseXp - (FLAG_WIDTH / 2) >  chanStartP - BORDER              &&
+                                mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
+                                mouseYp > h() - FLAG_HEIGHT;
 }
 
 
@@ -543,9 +548,9 @@ bool geWaveform::mouseOnEnd()
        int mouseXp  = frameToPixel(m_mouseX);
        int mouseYp  = frameToPixel(m_mouseY);
        int chanEndP = frameToPixel(m_chanEnd);
-  return mouseXp - (FLAG_WIDTH / 2) >= chanEndP - BORDER - FLAG_WIDTH &&
-         mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER              &&
-         mouseYp <= FLAG_HEIGHT + 1;
+       return mouseXp - (FLAG_WIDTH / 2) >= chanEndP - BORDER - FLAG_WIDTH &&
+                                mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER              &&
+                                mouseYp <= FLAG_HEIGHT + 1;
 }
 
 
@@ -556,7 +561,7 @@ bool geWaveform::mouseOnSelectionA()
 {
        int mouseXp = frameToPixel(m_mouseX);
        int selAp   = frameToPixel(m_selection.a);
-  return mouseXp >= selAp - (FLAG_WIDTH / 2) && mouseXp <= selAp + (FLAG_WIDTH / 2);
+       return mouseXp >= selAp - (FLAG_WIDTH / 2) && mouseXp <= selAp + (FLAG_WIDTH / 2);
 }
 
 
@@ -564,7 +569,7 @@ bool geWaveform::mouseOnSelectionB()
 {
        int mouseXp = frameToPixel(m_mouseX);
        int selBp   = frameToPixel(m_selection.b);
-  return mouseXp >= selBp - (FLAG_WIDTH / 2) && mouseXp <= selBp + (FLAG_WIDTH / 2);
+       return mouseXp >= selBp - (FLAG_WIDTH / 2) && mouseXp <= selBp + (FLAG_WIDTH / 2);
 }
 
 
@@ -573,11 +578,11 @@ bool geWaveform::mouseOnSelectionB()
 
 int geWaveform::pixelToFrame(int p)
 {
-  if (p <= 0)
-    return 0;
-  if (p > m_data.size)
-    return m_ch->wave->getSize() - 1;
-  return p * m_ratio;
+       if (p <= 0)
+               return 0;
+       if (p > m_data.size)
+               return m_ch->wave->getSize() - 1;
+       return p * m_ratio;
 }
 
 
@@ -586,7 +591,7 @@ int geWaveform::pixelToFrame(int p)
 
 int geWaveform::frameToPixel(int p)
 {
-  return ceil(p / m_ratio);
+       return ceil(p / m_ratio);
 }
 
 
@@ -595,9 +600,9 @@ int geWaveform::frameToPixel(int p)
 
 void geWaveform::fixSelection()
 {
-  if (m_selection.a > m_selection.b) // inverted m_selection
-    std::swap(m_selection.a, m_selection.b);
-  sampleEditor::setPlayHead(m_ch, m_selection.a);
+       if (m_selection.a > m_selection.b) // inverted m_selection
+               std::swap(m_selection.a, m_selection.b);
+       sampleEditor::setPlayHead(m_ch, m_selection.a);
 }
 
 
@@ -606,8 +611,8 @@ void geWaveform::fixSelection()
 
 void geWaveform::clearSel()
 {
-  m_selection.a = 0;
-  m_selection.b = 0;  
+       m_selection.a = 0;
+       m_selection.b = 0;  
 }
 
 
@@ -616,37 +621,37 @@ void geWaveform::clearSel()
 
 void geWaveform::setZoom(int type)
 {
-  if (!alloc(type == ZOOM_IN ? m_data.size * 2 : m_data.size / 2)) 
-    return;
+       if (!alloc(type == ZOOM_IN ? m_data.size * 2 : m_data.size / 2)) 
+               return;
 
-  size(m_data.size, h());
+       size(m_data.size, h());
 
-  /* Zoom to cursor. */
+       /* Zoom to cursor. */
        
        int newX = -frameToPixel(m_mouseX) + Fl::event_x();
        if (newX > BORDER)
                newX = BORDER;
        position(newX, y());
 
-  /* Avoid overflow when zooming out with scrollbar like that:
+       /* Avoid overflow when zooming out with scrollbar like that:
 
-       |----------[scrollbar]|
+               |----------[scrollbar]|
 
-  Offset vs smaller:
-  
-       |[wave------------| offset > 0  smaller = false
-       |[wave----]       | offset < 0, smaller = true
-       |-------------]   | offset < 0, smaller = false  */
+       Offset vs smaller:
+       
+               |[wave------------| offset > 0  smaller = false
+               |[wave----]       | offset < 0, smaller = true
+               |-------------]   | offset < 0, smaller = false  */
 
-  int parentW = parent()->w();
-  int thisW   = x() + w() - BORDER;           // visible width, not full width
+       int parentW = parent()->w();
+       int thisW   = x() + w() - BORDER;           // visible width, not full width
 
-  if (thisW < parentW)
-    position(x() + parentW - thisW, y());
-  if (smaller())
-    stretchToWindow();
+       if (thisW < parentW)
+               position(x() + parentW - thisW, y());
+       if (smaller())
+               stretchToWindow();
 
-  redraw();
+       redraw();
 }
 
 
@@ -655,10 +660,10 @@ void geWaveform::setZoom(int type)
 
 void geWaveform::stretchToWindow()
 {
-  int s = parent()->w();
-  alloc(s);
-  position(BORDER, y());
-  size(s, h());
+       int s = parent()->w();
+       alloc(s);
+       position(BORDER, y());
+       size(s, h());
 }
 
 
@@ -667,8 +672,8 @@ void geWaveform::stretchToWindow()
 
 void geWaveform::refresh()
 {
-  alloc(m_data.size, true); // force
-  redraw();
+       alloc(m_data.size, true); // force
+       redraw();
 }
 
 
@@ -677,7 +682,7 @@ void geWaveform::refresh()
 
 bool geWaveform::smaller()
 {
-  return w() < parent()->w();
+       return w() < parent()->w();
 }
 
 
@@ -686,10 +691,10 @@ bool geWaveform::smaller()
 
 void geWaveform::setGridLevel(int l)
 {
-  m_grid.points.clear();
-  m_grid.level = l;
-  alloc(m_data.size, true); // force alloc
-  redraw();
+       m_grid.points.clear();
+       m_grid.level = l;
+       alloc(m_data.size, true); // force alloc
+       redraw();
 }
 
 
@@ -698,7 +703,7 @@ void geWaveform::setGridLevel(int l)
 
 bool geWaveform::isSelected()
 {
-  return m_selection.a != m_selection.b;
+       return m_selection.a != m_selection.b;
 }
 
 
@@ -715,12 +720,19 @@ int geWaveform::getSize() { return m_data.size; }
 
 int geWaveform::getSelectionA()
 {
-  return m_selection.a;
+       return m_selection.a;
 }
 
 
 int geWaveform::getSelectionB()
 {
-  return m_selection.b;
+       return m_selection.b;
 }
 
+
+void geWaveform::selectAll()
+{
+       m_selection.a = 0;
+       m_selection.b = m_ch->wave->getSize() - 1;
+       redraw();
+}
index a4278601a0a7b427c65a20079ae12030fac0f50a..bfddf6e88f1f6e51309be7154f3a76a08741cd54 100644 (file)
@@ -58,14 +58,14 @@ private:
        Real graphic stuff from the underlying waveform. */
 
        struct
-  {
+       {
                int* sup;   // upper part of the waveform
                int* inf;   // lower part of the waveform
                int  size;  // width of the waveform to draw (in pixel)
        } m_data;
 
        struct
-  {
+       {
                bool snap;
                int level;
                std::vector<int> points;
@@ -96,8 +96,8 @@ private:
        bool mouseOnSelectionA();
        bool mouseOnSelectionB();
 
-       int pixelToFrame(int p);
-       int frameToPixel(int f);
+       int pixelToFrame(int p);  // TODO - move these to utils::, will be needed in actionEditor 
+       int frameToPixel(int f);  // TODO - move these to utils::, will be needed in actionEditor 
 
        /* fixSelection
        Helper function which flattens the selection if it was made from right to left 
@@ -116,19 +116,21 @@ private:
 
        bool smaller();
 
-  /* snap
-  Snaps a point at 'pos' pixel. */
+       /* snap
+       Snaps a point at 'pos' pixel. */
+
+       int snap(int pos);
 
-  int snap(int pos);
+       /* draw*
+       Drawing functions. */
 
-  /* draw*
-  Drawing functions. */
+       void drawSelection();
+       void drawWaveform(int from, int to);
+       void drawGrid(int from, int to);
+       void drawStartEndPoints();
+       void drawPlayHead();
 
-  void drawSelection();
-  void drawWaveform(int from, int to);
-  void drawGrid(int from, int to);
-  void drawStartEndPoints();
-  void drawPlayHead();
+       void selectAll();
 
 public:
 
@@ -172,8 +174,8 @@ public:
 
        void setGridLevel(int l);
 
-  void setSnap(bool v);
-  bool getSnap();
+       void setSnap(bool v);
+       bool getSnap();
        int getSize();
 
        /* isSelected
diff --git a/src/utils/time.cpp b/src/utils/time.cpp
new file mode 100644 (file)
index 0000000..e28a706
--- /dev/null
@@ -0,0 +1,43 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <chrono>
+#include <thread>
+#include "time.h"
+
+
+namespace giada {
+namespace u     {
+namespace time 
+{
+void sleep(int millisecs)
+{
+       std::this_thread::sleep_for(std::chrono::milliseconds(millisecs));
+}
+}}};  // giada::u::time::
diff --git a/src/utils/time.h b/src/utils/time.h
new file mode 100644 (file)
index 0000000..5ebd453
--- /dev/null
@@ -0,0 +1,42 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_UTILS_TIME_H
+#define G_UTILS_TIME_H
+
+
+namespace giada {
+namespace u     {
+namespace time 
+{
+void sleep(int millisecs);
+}}};
+
+
+#endif
\ No newline at end of file
index a84c94572e2a53a6e2333c42f1339056de8a29b7..da5516258217b1f20fbc11208cb7a4cf7a59eee2 100644 (file)
@@ -10,221 +10,222 @@ using namespace giada::m;
 
 TEST_CASE("Test Patch class")
 {
-  string filename = "./test-patch.json";
-
-  SECTION("test write")
-  {
-    patch::action_t  action1;
-    patch::action_t  action2;
-    patch::channel_t channel1;
-    patch::channel_t channel2;
-    patch::column_t  column;
+       string filename = "./test-patch.json";
+
+       SECTION("test write")
+       {
+               patch::action_t  action1;
+               patch::action_t  action2;
+               patch::channel_t channel1;
+               patch::column_t  column;
 #ifdef WITH_VST
-    patch::plugin_t  plugin1;
-    patch::plugin_t  plugin2;
-    patch::plugin_t  plugin3;
+               patch::plugin_t  plugin1;
+               patch::plugin_t  plugin2;
+               patch::plugin_t  plugin3;
 #endif
 
-    action1.type   = 0;
-    action1.frame  = 50000;
-    action1.fValue = 0.3f;
-    action1.iValue = 1000;
-    action2.type   = 2;
-    action2.frame  = 589;
-    action2.fValue = 1.0f;
-    action2.iValue = 130;
-    channel1.actions.push_back(action1);
-    channel1.actions.push_back(action2);
+               action1.type   = 0;
+               action1.frame  = 50000;
+               action1.fValue = 0.3f;
+               action1.iValue = 1000;
+               action2.type   = 2;
+               action2.frame  = 589;
+               action2.fValue = 1.0f;
+               action2.iValue = 130;
+               channel1.actions.push_back(action1);
+               channel1.actions.push_back(action2);
 
 #ifdef WITH_VST
-    plugin1.path   = "/path/to/plugin1";
-    plugin1.bypass = false;
-    plugin1.params.push_back(0.0f);
-    plugin1.params.push_back(0.1f);
-    plugin1.params.push_back(0.2f);
-    channel1.plugins.push_back(plugin1);
-
-    plugin2.path   = "/another/path/to/plugin2";
-    plugin2.bypass = true;
-    plugin2.params.push_back(0.6f);
-    plugin2.params.push_back(0.6f);
-    plugin2.params.push_back(0.6f);
-    plugin2.params.push_back(0.0f);
-    plugin2.params.push_back(1.0f);
-    plugin2.params.push_back(1.0f);
-    plugin2.params.push_back(0.333f);
-    channel1.plugins.push_back(plugin2);
+               plugin1.path   = "/path/to/plugin1";
+               plugin1.bypass = false;
+               plugin1.params.push_back(0.0f);
+               plugin1.params.push_back(0.1f);
+               plugin1.params.push_back(0.2f);
+               channel1.plugins.push_back(plugin1);
+
+               plugin2.path   = "/another/path/to/plugin2";
+               plugin2.bypass = true;
+               plugin2.params.push_back(0.6f);
+               plugin2.params.push_back(0.6f);
+               plugin2.params.push_back(0.6f);
+               plugin2.params.push_back(0.0f);
+               plugin2.params.push_back(1.0f);
+               plugin2.params.push_back(1.0f);
+               plugin2.params.push_back(0.333f);
+               channel1.plugins.push_back(plugin2);
 #endif
 
-    channel1.type              = CHANNEL_SAMPLE;
-    channel1.index             = 666;
-    channel1.column            = 0;
-    channel1.mute              = 0;
-    channel1.mute_s            = 0;
-    channel1.solo              = 0;
-    channel1.volume            = 1.0f;
-    channel1.pan               = 0.5f;
-    channel1.midiIn            = true;
-    channel1.midiInKeyPress    = UINT32_MAX;  // check maximum value
-    channel1.midiInKeyRel      = 1;
-    channel1.midiInKill        = 2;
-    channel1.midiInArm         = 11;
-    channel1.midiInVolume      = 3;
-    channel1.midiInMute        = 4;
-    channel1.midiInSolo        = 5;
-    channel1.midiOutL          = true;
-    channel1.midiOutLplaying   = 7;
-    channel1.midiOutLmute      = 8;
-    channel1.midiOutLsolo      = 9;
-    channel1.samplePath        = "/tmp/test.wav";
-    channel1.key               = 666;
-    channel1.mode              = 0;
-    channel1.begin             = 0;
-    channel1.end               = 0;
-    channel1.boost             = 0;
-    channel1.recActive         = 0;
-    channel1.pitch             = 1.2f;
-    channel1.midiInReadActions = 0;
-    channel1.midiInPitch       = 0;
-    channel1.midiOut           = 0;
-    channel1.midiOutChan       = 5;
-    patch::channels.push_back(channel1);
-
-    column.index = 0;
-    column.width = 500;
-    patch::columns.push_back(column);
-
-    patch::header       = "GPTCH";
-    patch::version      = "1.0";
-    patch::versionMajor = 6;
-    patch::versionMinor = 6;
-    patch::versionPatch = 6;
-    patch::name         = "test patch";
-    patch::bpm          = 100.0f;
-    patch::bars         = 4;
-    patch::beats        = 23;
-    patch::quantize     = 1;
-    patch::masterVolIn  = 1.0f;
-    patch::masterVolOut = 0.7f;
-    patch::metronome    = 0;
-    patch::lastTakeId   = 0;
-    patch::samplerate   = 44100;
+               channel1.type              = CHANNEL_SAMPLE;
+               channel1.index             = 666;
+               channel1.size              = G_GUI_CHANNEL_H_1;
+               channel1.column            = 0;
+               channel1.mute              = 0;
+               channel1.mute_s            = 0;
+               channel1.solo              = 0;
+               channel1.volume            = 1.0f;
+               channel1.pan               = 0.5f;
+               channel1.midiIn            = true;
+               channel1.midiInKeyPress    = UINT32_MAX;  // check maximum value
+               channel1.midiInKeyRel      = 1;
+               channel1.midiInKill        = 2;
+               channel1.midiInArm         = 11;
+               channel1.midiInVolume      = 3;
+               channel1.midiInMute        = 4;
+               channel1.midiInSolo        = 5;
+               channel1.midiOutL          = true;
+               channel1.midiOutLplaying   = 7;
+               channel1.midiOutLmute      = 8;
+               channel1.midiOutLsolo      = 9;
+               channel1.samplePath        = "/tmp/test.wav";
+               channel1.key               = 666;
+               channel1.mode              = 0;
+               channel1.begin             = 0;
+               channel1.end               = 0;
+               channel1.boost             = 0;
+               channel1.recActive         = 0;
+               channel1.pitch             = 1.2f;
+               channel1.midiInReadActions = 0;
+               channel1.midiInPitch       = 0;
+               channel1.midiOut           = 0;
+               channel1.midiOutChan       = 5;
+               patch::channels.push_back(channel1);
+
+               column.index = 0;
+               column.width = 500;
+               patch::columns.push_back(column);
+
+               patch::header       = "GPTCH";
+               patch::version      = "1.0";
+               patch::versionMajor = 6;
+               patch::versionMinor = 6;
+               patch::versionPatch = 6;
+               patch::name         = "test patch";
+               patch::bpm          = 100.0f;
+               patch::bars         = 4;
+               patch::beats        = 23;
+               patch::quantize     = 1;
+               patch::masterVolIn  = 1.0f;
+               patch::masterVolOut = 0.7f;
+               patch::metronome    = 0;
+               patch::lastTakeId   = 0;
+               patch::samplerate   = 44100;
 
 #ifdef WITH_VST
 
-    patch::masterInPlugins.push_back(plugin1);
-    patch::masterOutPlugins.push_back(plugin2);
+               patch::masterInPlugins.push_back(plugin1);
+               patch::masterOutPlugins.push_back(plugin2);
 
 #endif
 
-    REQUIRE(patch::write(filename) == 1);
-  }
-
-  SECTION("test read")
-  {
-    REQUIRE(patch::read(filename) == PATCH_READ_OK);
-    REQUIRE(patch::header == "GPTCH");
-    REQUIRE(patch::version == "1.0");
-    REQUIRE(patch::versionMajor == 6);
-    REQUIRE(patch::versionMinor == 6);
-    REQUIRE(patch::versionPatch == 6);
-    REQUIRE(patch::name == "test patch");
-    REQUIRE(patch::bpm == Approx(100.0f));
-    REQUIRE(patch::bars == 4);
-    REQUIRE(patch::beats == 23);
-    REQUIRE(patch::quantize == 1);
-    REQUIRE(patch::masterVolIn == Approx(1.0f));
-    REQUIRE(patch::masterVolOut == Approx(0.7f));
-    REQUIRE(patch::metronome == 0);
-    REQUIRE(patch::lastTakeId == 0);
-    REQUIRE(patch::samplerate == 44100);
-
-    patch::column_t column0 = patch::columns.at(0);
-    REQUIRE(column0.index == 0);
-    REQUIRE(column0.width == 500);
-
-    patch::channel_t channel0 = patch::channels.at(0);
-    REQUIRE(channel0.type == CHANNEL_SAMPLE);
-    REQUIRE(channel0.index == 666);
-    REQUIRE(channel0.column == 0);
-    REQUIRE(channel0.mute == 0);
-    REQUIRE(channel0.mute_s == 0);
-    REQUIRE(channel0.solo == 0);
-    REQUIRE(channel0.volume == Approx(1.0f));
-    REQUIRE(channel0.pan == Approx(0.5f));
-    REQUIRE(channel0.midiIn == true);
-    REQUIRE(channel0.midiInKeyPress == UINT32_MAX);
-    REQUIRE(channel0.midiInKeyRel == 1);
-    REQUIRE(channel0.midiInKill == 2);
-    REQUIRE(channel0.midiInArm == 11);
-    REQUIRE(channel0.midiInVolume == 3);
-    REQUIRE(channel0.midiInMute == 4);
-    REQUIRE(channel0.midiInSolo == 5);
-    REQUIRE(channel0.midiOutL == true);
-    REQUIRE(channel0.midiOutLplaying == 7);
-    REQUIRE(channel0.midiOutLmute == 8);
-    REQUIRE(channel0.midiOutLsolo == 9);
-    REQUIRE(channel0.samplePath == "/tmp/test.wav");
-    REQUIRE(channel0.key == 666);
-    REQUIRE(channel0.mode == 0);
-    REQUIRE(channel0.begin == 0);
-    REQUIRE(channel0.end == 0);
-    REQUIRE(channel0.boost == 1.0f);
-    REQUIRE(channel0.recActive == 0);
-    REQUIRE(channel0.pitch == Approx(1.2f));
-    REQUIRE(channel0.midiInReadActions == 0);
-    REQUIRE(channel0.midiInPitch == 0);
-    REQUIRE(channel0.midiOut == 0);
-    REQUIRE(channel0.midiOutChan == 5);
-
-    patch::action_t action0 = channel0.actions.at(0);
-    REQUIRE(action0.type == 0);
-    REQUIRE(action0.frame == 50000);
-    REQUIRE(action0.fValue == Approx(0.3f));
-    REQUIRE(action0.iValue == 1000);
-
-    patch::action_t action1 = channel0.actions.at(1);
-    REQUIRE(action1.type == 2);
-    REQUIRE(action1.frame == 589);
-    REQUIRE(action1.fValue == Approx(1.0f));
-    REQUIRE(action1.iValue == 130);
+               REQUIRE(patch::write(filename) == 1);
+       }
+
+       SECTION("test read")
+       {
+               REQUIRE(patch::read(filename) == PATCH_READ_OK);
+               REQUIRE(patch::header == "GPTCH");
+               REQUIRE(patch::version == "1.0");
+               REQUIRE(patch::versionMajor == 6);
+               REQUIRE(patch::versionMinor == 6);
+               REQUIRE(patch::versionPatch == 6);
+               REQUIRE(patch::name == "test patch");
+               REQUIRE(patch::bpm == Approx(100.0f));
+               REQUIRE(patch::bars == 4);
+               REQUIRE(patch::beats == 23);
+               REQUIRE(patch::quantize == 1);
+               REQUIRE(patch::masterVolIn == Approx(1.0f));
+               REQUIRE(patch::masterVolOut == Approx(0.7f));
+               REQUIRE(patch::metronome == 0);
+               REQUIRE(patch::lastTakeId == 0);
+               REQUIRE(patch::samplerate == 44100);
+
+               patch::column_t column0 = patch::columns.at(0);
+               REQUIRE(column0.index == 0);
+               REQUIRE(column0.width == 500);
+
+               patch::channel_t channel0 = patch::channels.at(0);
+               REQUIRE(channel0.type == CHANNEL_SAMPLE);
+               REQUIRE(channel0.index == 666);
+               REQUIRE(channel0.size == G_GUI_CHANNEL_H_1);
+               REQUIRE(channel0.column == 0);
+               REQUIRE(channel0.mute == 0);
+               REQUIRE(channel0.mute_s == 0);
+               REQUIRE(channel0.solo == 0);
+               REQUIRE(channel0.volume == Approx(1.0f));
+               REQUIRE(channel0.pan == Approx(0.5f));
+               REQUIRE(channel0.midiIn == true);
+               REQUIRE(channel0.midiInKeyPress == UINT32_MAX);
+               REQUIRE(channel0.midiInKeyRel == 1);
+               REQUIRE(channel0.midiInKill == 2);
+               REQUIRE(channel0.midiInArm == 11);
+               REQUIRE(channel0.midiInVolume == 3);
+               REQUIRE(channel0.midiInMute == 4);
+               REQUIRE(channel0.midiInSolo == 5);
+               REQUIRE(channel0.midiOutL == true);
+               REQUIRE(channel0.midiOutLplaying == 7);
+               REQUIRE(channel0.midiOutLmute == 8);
+               REQUIRE(channel0.midiOutLsolo == 9);
+               REQUIRE(channel0.samplePath == "/tmp/test.wav");
+               REQUIRE(channel0.key == 666);
+               REQUIRE(channel0.mode == 0);
+               REQUIRE(channel0.begin == 0);
+               REQUIRE(channel0.end == 0);
+               REQUIRE(channel0.boost == 1.0f);
+               REQUIRE(channel0.recActive == 0);
+               REQUIRE(channel0.pitch == Approx(1.2f));
+               REQUIRE(channel0.midiInReadActions == 0);
+               REQUIRE(channel0.midiInPitch == 0);
+               REQUIRE(channel0.midiOut == 0);
+               REQUIRE(channel0.midiOutChan == 5);
+
+               patch::action_t action0 = channel0.actions.at(0);
+               REQUIRE(action0.type == 0);
+               REQUIRE(action0.frame == 50000);
+               REQUIRE(action0.fValue == Approx(0.3f));
+               REQUIRE(action0.iValue == 1000);
+
+               patch::action_t action1 = channel0.actions.at(1);
+               REQUIRE(action1.type == 2);
+               REQUIRE(action1.frame == 589);
+               REQUIRE(action1.fValue == Approx(1.0f));
+               REQUIRE(action1.iValue == 130);
 
 #ifdef WITH_VST
-    patch::plugin_t plugin0 = channel0.plugins.at(0);
-    REQUIRE(plugin0.path   == "/path/to/plugin1");
-    REQUIRE(plugin0.bypass == false);
-    REQUIRE(plugin0.params.at(0) == Approx(0.0f));
-    REQUIRE(plugin0.params.at(1) == Approx(0.1f));
-    REQUIRE(plugin0.params.at(2) == Approx(0.2f));
-
-    patch::plugin_t plugin1 = channel0.plugins.at(1);
-    REQUIRE(plugin1.path == "/another/path/to/plugin2");
-    REQUIRE(plugin1.bypass == true);
-    REQUIRE(plugin1.params.at(0) == Approx(0.6f));
-    REQUIRE(plugin1.params.at(1) == Approx(0.6f));
-    REQUIRE(plugin1.params.at(2) == Approx(0.6f));
-    REQUIRE(plugin1.params.at(3) == Approx(0.0f));
-    REQUIRE(plugin1.params.at(4) == Approx(1.0f));
-    REQUIRE(plugin1.params.at(5) == Approx(1.0f));
-    REQUIRE(plugin1.params.at(6) == Approx(0.333f));
-
-    patch::plugin_t masterPlugin0 = patch::masterInPlugins.at(0);
-    REQUIRE(masterPlugin0.path   == "/path/to/plugin1");
-    REQUIRE(masterPlugin0.bypass == false);
-    REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f));
-    REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f));
-    REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f));
-
-    patch::plugin_t masterPlugin1 = patch::masterOutPlugins.at(0);
-    REQUIRE(masterPlugin1.path == "/another/path/to/plugin2");
-    REQUIRE(masterPlugin1.bypass == true);
-    REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f));
-    REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f));
-    REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f));
-    REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f));
-    REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f));
-    REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f));
-    REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f));
+               patch::plugin_t plugin0 = channel0.plugins.at(0);
+               REQUIRE(plugin0.path   == "/path/to/plugin1");
+               REQUIRE(plugin0.bypass == false);
+               REQUIRE(plugin0.params.at(0) == Approx(0.0f));
+               REQUIRE(plugin0.params.at(1) == Approx(0.1f));
+               REQUIRE(plugin0.params.at(2) == Approx(0.2f));
+
+               patch::plugin_t plugin1 = channel0.plugins.at(1);
+               REQUIRE(plugin1.path == "/another/path/to/plugin2");
+               REQUIRE(plugin1.bypass == true);
+               REQUIRE(plugin1.params.at(0) == Approx(0.6f));
+               REQUIRE(plugin1.params.at(1) == Approx(0.6f));
+               REQUIRE(plugin1.params.at(2) == Approx(0.6f));
+               REQUIRE(plugin1.params.at(3) == Approx(0.0f));
+               REQUIRE(plugin1.params.at(4) == Approx(1.0f));
+               REQUIRE(plugin1.params.at(5) == Approx(1.0f));
+               REQUIRE(plugin1.params.at(6) == Approx(0.333f));
+
+               patch::plugin_t masterPlugin0 = patch::masterInPlugins.at(0);
+               REQUIRE(masterPlugin0.path   == "/path/to/plugin1");
+               REQUIRE(masterPlugin0.bypass == false);
+               REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f));
+               REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f));
+               REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f));
+
+               patch::plugin_t masterPlugin1 = patch::masterOutPlugins.at(0);
+               REQUIRE(masterPlugin1.path == "/another/path/to/plugin2");
+               REQUIRE(masterPlugin1.bypass == true);
+               REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f));
+               REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f));
+               REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f));
+               REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f));
+               REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f));
+               REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f));
+               REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f));
 #endif
-  }
+       }
 }