From: Jaromír Mikeš Date: Sun, 15 Jan 2017 17:50:59 +0000 (+0100) Subject: New upstream version 0.13.2~dfsg1 X-Git-Tag: archive/raspbian/0.15.4+ds1-1+rpi1^2~12^2~12 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=0cf29addd1c52a50e2f11c0611b841d3756f537b;p=giada.git New upstream version 0.13.2~dfsg1 --- diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5c770bc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -sudo: required - -dist: trusty - -language: cpp - -compiler: gcc - -notifications: - email: - recipients: - - giadaloopmachine@gmail.com - on_success: never - on_failure: always - -before_install: - - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for gcc 6 - - sudo apt-get update -qq - - sudo apt-get install -y gcc-6 g++-6 libsndfile1-dev libsamplerate0-dev libfltk1.3-dev libasound2-dev libxpm-dev libpulse-dev libjack-dev libxrandr-dev libx11-dev libxinerama-dev libxcursor-dev - -before_script: - - sudo ln -f -s /usr/bin/g++-6 /usr/bin/g++ - - # Download and build latest version of RtMidi - - - wget http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-2.1.0.tar.gz - - tar -xvf rtmidi-2.1.0.tar.gz - - cd rtmidi-2.1.0 && ./configure --with-jack --with-alsa && make && sudo make install || true - - cd .. - - # Download and install latest version of Jansson - - - wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz - - tar -xvf jansson-2.7.tar.gz - - cd jansson-2.7 && ./configure && make && sudo make install || true - - sudo ldconfig - - cd .. - - # Download midimaps package for testing purposes - - - wget https://github.com/monocasual/giada-midimaps/archive/master.zip -O giada-midimaps-master.zip - - unzip giada-midimaps-master.zip - - mkdir -p $HOME/.giada/midimaps - - cp giada-midimaps-master/midimaps/* $HOME/.giada/midimaps - - # Download vst plugin for testing purposes - - - wget http://www.discodsp.com/download/?id=18 -O bliss-linux.zip - - unzip bliss-linux.zip -d bliss-linux - - cp bliss-linux/64-bit/Bliss64Demo.so . - - # Build Giada. Note the CFLAGS: optimization levels are set to O1 in order - # not to throw up nasty errors from JUCE modules. - - - ./autogen.sh - - ./configure CXXFLAGS='-g -O1' --target=linux --enable-vst - -script: make && make check - -after_failure: cat $TRAVIS_BUILD_DIR/test-suite.log diff --git a/ChangeLog b/ChangeLog index 22878ce..65e29a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,19 @@ -------------------------------------------------------------------------------- +0.13.2 --- 2017 . 01 . 14 +- MIDI learn for plugins parameters +- Toggle hidden files in File Browser +- Fix broken compilation when build without VST support +- Make sure PluginChooser window has a sane size +- Decouple Recorder from any global variable +- Better source code organization +- Make plugin creation more robust +- More source code reorganization +- Fix crash on clicking scrollbar arrows (GitHub #53) +- Fix crash when doubling/dividing length while recording (GitHub #110) + + 0.13.1 --- 2016 . 11 . 16 - Input MIDI to MIDI channels/plugins - Refinements to show/hide 'R' button's dynamics diff --git a/Makefile.am b/Makefile.am index 7990158..edb15a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,6 +55,8 @@ src/glue/storage.h \ src/glue/storage.cpp \ src/glue/channel.h \ src/glue/channel.cpp \ +src/glue/plugin.h \ +src/glue/plugin.cpp \ src/gui/dialogs/gd_keyGrabber.h \ src/gui/dialogs/gd_keyGrabber.cpp \ src/gui/dialogs/gd_about.h \ @@ -81,28 +83,30 @@ src/gui/dialogs/gd_editor.h \ src/gui/dialogs/gd_editor.cpp \ src/gui/dialogs/gd_pluginWindowGUI.h \ src/gui/dialogs/gd_pluginWindowGUI.cpp \ -src/gui/dialogs/gd_midiOutput.h \ -src/gui/dialogs/gd_midiOutput.cpp \ -src/gui/dialogs/gd_midiInput.h \ -src/gui/dialogs/gd_midiInput.cpp \ src/gui/dialogs/gd_actionEditor.h \ src/gui/dialogs/gd_actionEditor.cpp \ src/gui/dialogs/gd_pluginChooser.h \ src/gui/dialogs/gd_pluginChooser.cpp \ -src/gui/elems/ge_column.h \ -src/gui/elems/ge_column.cpp \ -src/gui/elems/sampleChannel.h \ -src/gui/elems/sampleChannel.cpp \ -src/gui/elems/midiChannel.h \ -src/gui/elems/midiChannel.cpp \ -src/gui/elems/ge_midiIoTools.h \ -src/gui/elems/ge_midiIoTools.cpp \ +src/gui/dialogs/midiIO/midiOutputBase.h \ +src/gui/dialogs/midiIO/midiOutputBase.cpp \ +src/gui/dialogs/midiIO/midiOutputSampleCh.h \ +src/gui/dialogs/midiIO/midiOutputSampleCh.cpp \ +src/gui/dialogs/midiIO/midiOutputMidiCh.h \ +src/gui/dialogs/midiIO/midiOutputMidiCh.cpp \ +src/gui/dialogs/midiIO/midiInputBase.h \ +src/gui/dialogs/midiIO/midiInputBase.cpp \ +src/gui/dialogs/midiIO/midiInputChannel.h \ +src/gui/dialogs/midiIO/midiInputChannel.cpp \ +src/gui/dialogs/midiIO/midiInputMaster.h \ +src/gui/dialogs/midiIO/midiInputMaster.cpp \ +src/gui/elems/midiLearner.h \ +src/gui/elems/midiLearner.cpp \ src/gui/elems/ge_mixed.h \ src/gui/elems/ge_mixed.cpp \ src/gui/elems/ge_waveform.h \ src/gui/elems/ge_waveform.cpp \ -src/gui/elems/ge_browser.h \ -src/gui/elems/ge_browser.cpp \ +src/gui/elems/browser.h \ +src/gui/elems/browser.cpp \ src/gui/elems/baseActionEditor.h \ src/gui/elems/baseActionEditor.cpp \ src/gui/elems/envelopeEditor.h \ @@ -113,28 +117,46 @@ src/gui/elems/noteEditor.h \ src/gui/elems/noteEditor.cpp \ src/gui/elems/pianoItem.h \ src/gui/elems/pianoItem.cpp \ -src/gui/elems/channel.h \ -src/gui/elems/channel.cpp \ src/gui/elems/muteEditor.h \ src/gui/elems/muteEditor.cpp \ src/gui/elems/actionEditor.h \ src/gui/elems/actionEditor.cpp \ src/gui/elems/ge_window.h \ src/gui/elems/ge_window.cpp \ -src/gui/elems/ge_status.h \ -src/gui/elems/ge_status.cpp \ -src/gui/elems/ge_keyboard.h \ -src/gui/elems/ge_keyboard.cpp \ src/gui/elems/ge_waveTools.h \ src/gui/elems/ge_waveTools.cpp \ -src/gui/elems/ge_modeBox.h \ -src/gui/elems/ge_modeBox.cpp \ -src/gui/elems/ge_controller.h \ -src/gui/elems/ge_controller.cpp \ -src/gui/elems/channelButton.h \ -src/gui/elems/channelButton.cpp \ src/gui/elems/ge_pluginBrowser.h \ src/gui/elems/ge_pluginBrowser.cpp \ +src/gui/elems/mainWindow/mainIO.h \ +src/gui/elems/mainWindow/mainIO.cpp \ +src/gui/elems/mainWindow/mainMenu.h \ +src/gui/elems/mainWindow/mainMenu.cpp \ +src/gui/elems/mainWindow/mainTimer.h \ +src/gui/elems/mainWindow/mainTimer.cpp \ +src/gui/elems/mainWindow/mainTransport.h \ +src/gui/elems/mainWindow/mainTransport.cpp \ +src/gui/elems/mainWindow/beatMeter.h \ +src/gui/elems/mainWindow/beatMeter.cpp \ +src/gui/elems/mainWindow/keyboard/channelMode.h \ +src/gui/elems/mainWindow/keyboard/channelMode.cpp \ +src/gui/elems/mainWindow/keyboard/channelButton.h \ +src/gui/elems/mainWindow/keyboard/channelButton.cpp \ +src/gui/elems/mainWindow/keyboard/channelStatus.h \ +src/gui/elems/mainWindow/keyboard/channelStatus.cpp \ +src/gui/elems/mainWindow/keyboard/keyboard.h \ +src/gui/elems/mainWindow/keyboard/keyboard.cpp \ +src/gui/elems/mainWindow/keyboard/column.h \ +src/gui/elems/mainWindow/keyboard/column.cpp \ +src/gui/elems/mainWindow/keyboard/sampleChannel.h \ +src/gui/elems/mainWindow/keyboard/sampleChannel.cpp \ +src/gui/elems/mainWindow/keyboard/midiChannel.h \ +src/gui/elems/mainWindow/keyboard/midiChannel.cpp \ +src/gui/elems/mainWindow/keyboard/channel.h \ +src/gui/elems/mainWindow/keyboard/channel.cpp \ +src/gui/elems/basics/scroll.h \ +src/gui/elems/basics/scroll.cpp \ +src/gui/elems/basics/boxtypes.h \ +src/gui/elems/basics/boxtypes.cpp \ src/utils/log.h \ src/utils/log.cpp \ src/utils/gui.h \ @@ -147,14 +169,14 @@ src/utils/string.cpp if WITH_VST giada_SOURCES += \ -src/deps/juce/juce_audio_basics/juce_audio_basics.cpp \ -src/deps/juce/juce_audio_processors/juce_audio_processors.cpp \ -src/deps/juce/juce_core/juce_core.cpp \ -src/deps/juce/juce_data_structures/juce_data_structures.cpp \ -src/deps/juce/juce_events/juce_events.cpp \ -src/deps/juce/juce_graphics/juce_graphics.cpp \ -src/deps/juce/juce_gui_basics/juce_gui_basics.cpp \ -src/deps/juce/juce_gui_extra/juce_gui_extra.cpp +src/deps/juce/modules/juce_audio_basics/juce_audio_basics.cpp \ +src/deps/juce/modules/juce_audio_processors/juce_audio_processors.cpp \ +src/deps/juce/modules/juce_core/juce_core.cpp \ +src/deps/juce/modules/juce_data_structures/juce_data_structures.cpp \ +src/deps/juce/modules/juce_events/juce_events.cpp \ +src/deps/juce/modules/juce_graphics/juce_graphics.cpp \ +src/deps/juce/modules/juce_gui_basics/juce_gui_basics.cpp \ +src/deps/juce/modules/juce_gui_extra/juce_gui_extra.cpp endif # Check for environment: WITH_VST, LINUX, WINDOWS and OSX are varibles defined @@ -173,7 +195,7 @@ giada_CPPFLAGS = if WITH_VST giada_CPPFLAGS += \ - -I./src/deps/juce \ + -I./src/deps/juce/modules \ -I./src/deps/vst \ -I/usr/include \ -I/usr/include/freetype2 \ @@ -270,14 +292,14 @@ src/utils/log.cpp if WITH_VST giada_tests_SOURCES += \ -src/deps/juce/juce_audio_basics/juce_audio_basics.cpp \ -src/deps/juce/juce_audio_processors/juce_audio_processors.cpp \ -src/deps/juce/juce_core/juce_core.cpp \ -src/deps/juce/juce_data_structures/juce_data_structures.cpp \ -src/deps/juce/juce_events/juce_events.cpp \ -src/deps/juce/juce_graphics/juce_graphics.cpp \ -src/deps/juce/juce_gui_basics/juce_gui_basics.cpp \ -src/deps/juce/juce_gui_extra/juce_gui_extra.cpp +src/deps/juce/modules/juce_audio_basics/juce_audio_basics.cpp \ +src/deps/juce/modules/juce_audio_processors/juce_audio_processors.cpp \ +src/deps/juce/modules/juce_core/juce_core.cpp \ +src/deps/juce/modules/juce_data_structures/juce_data_structures.cpp \ +src/deps/juce/modules/juce_events/juce_events.cpp \ +src/deps/juce/modules/juce_graphics/juce_graphics.cpp \ +src/deps/juce/modules/juce_gui_basics/juce_gui_basics.cpp \ +src/deps/juce/modules/juce_gui_extra/juce_gui_extra.cpp endif giada_tests_LDADD = -ljansson -lsndfile -lsamplerate -lfltk -lXext -lX11 -lXft \ @@ -288,7 +310,7 @@ giada_tests_CXXFLAGS = -std=c++11 if WITH_VST giada_tests_CPPFLAGS = \ - -I./src/deps/juce \ + -I./src/deps/juce/modules \ -I./src/deps/vst \ -I/usr/include \ -I/usr/include/freetype2 \ diff --git a/src/core/channel.cpp b/src/core/channel.cpp index bcbafeb..95ad99a 100644 --- a/src/core/channel.cpp +++ b/src/core/channel.cpp @@ -28,7 +28,7 @@ #include "../utils/log.h" -#include "../gui/elems/channel.h" +#include "../gui/elems/mainWindow/keyboard/channel.h" #include "channel.h" #include "pluginHost.h" #include "plugin.h" @@ -69,6 +69,7 @@ Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf) mute (false), solo (false), hasActions (false), + readActions (false), armed (false), recStatus (REC_STOPPED), vChan (nullptr), @@ -147,8 +148,10 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex) for (unsigned i=0; ichan == src->index) + if (a->chan == src->index) { G_Recorder.rec(index, a->type, a->frame, a->iValue, a->fValue); + hasActions = true; + } } } } @@ -255,14 +258,14 @@ int Channel::writePatch(int i, bool isProject, Patch *patch) unsigned numPlugs = pluginHost->countPlugins(PluginHost::CHANNEL, this); for (unsigned i=0; igetPluginByIndex(i, PluginHost::CHANNEL, this); - if (pPlugin->getStatus()) { - Patch::plugin_t pp; - pp.path = pPlugin->getUniqueId(); - pp.bypass = pPlugin->isBypassed(); - for (int k=0; kgetNumParameters(); k++) - pp.params.push_back(pPlugin->getParameter(k)); - pch.plugins.push_back(pp); - } + Patch::plugin_t pp; + pp.path = pPlugin->getUniqueId(); + pp.bypass = pPlugin->isBypassed(); + for (int k=0; kgetNumParameters(); k++) + pp.params.push_back(pPlugin->getParameter(k)); + for (unsigned k=0; kmidiInParams.size(); k++) + pp.midiInParams.push_back(pPlugin->midiInParams.at(k)); + pch.plugins.push_back(pp); } #endif @@ -305,6 +308,7 @@ int Channel::readPatch(const string &path, int i, Patch *patch, for (unsigned k=0; kactions.size(); k++) { Patch::action_t *ac = &pch->actions.at(k); G_Recorder.rec(index, ac->type, ac->frame, ac->iValue, ac->fValue); + hasActions = true; } #ifdef WITH_VST @@ -313,14 +317,17 @@ int Channel::readPatch(const string &path, int i, Patch *patch, Patch::plugin_t *ppl = &pch->plugins.at(k); Plugin *plugin = pluginHost->addPlugin(ppl->path, PluginHost::CHANNEL, pluginMutex, this); - if (plugin != nullptr) { - plugin->setBypass(ppl->bypass); - for (unsigned j=0; jparams.size(); j++) - plugin->setParameter(j, ppl->params.at(j)); - ret &= 1; - } - else - ret &= 0; + if (plugin == nullptr) { + ret &= 0; + continue; + } + plugin->setBypass(ppl->bypass); + for (unsigned j=0; jparams.size(); j++) + plugin->setParameter(j, ppl->params.at(j)); + plugin->midiInParams.clear(); + for (unsigned j=0; jmidiInParams.size(); j++) + plugin->midiInParams.push_back(ppl->midiInParams.at(j)); + ret &= 1; } #endif diff --git a/src/core/channel.h b/src/core/channel.h index df9fe64..2df3d14 100644 --- a/src/core/channel.h +++ b/src/core/channel.h @@ -37,7 +37,7 @@ #include "recorder.h" #ifdef WITH_VST - #include "../deps/juce/config.h" + #include "../deps/juce-config.h" #endif @@ -143,10 +143,10 @@ public: /* quantize * start channel according to quantizer. Index = array index of - * mixer::channels, used by recorder. LocalFrame = frame within buffer. - * GloalFrame = actual frame from mixer. */ + * mixer::channels, used by recorder. LocalFrame = frame within the current + * buffer. */ - virtual void quantize(int index, int localFrame, int globalFrame) = 0; + virtual void quantize(int index, int localFrame, class Mixer *m) = 0; /* onZero * action to do when frame goes to zero, i.e. sequencer restart. */ @@ -213,6 +213,7 @@ public: bool mute; // global mute bool solo; bool hasActions; // has something recorded + bool readActions; // read what's recorded bool armed; // armed for recording int recStatus; // status of recordings (waiting, ending, ...) float *vChan; // virtual channel diff --git a/src/core/conf.cpp b/src/core/conf.cpp index 021549b..1a690ac 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -154,6 +154,11 @@ void Conf::init() sampleEditorW = 640; sampleEditorH = 480; + midiInputX = 0; + midiInputY = 0; + midiInputW = G_DEFAULT_MIDI_INPUT_UI_W; + midiInputH = G_DEFAULT_MIDI_INPUT_UI_H; + pianoRollY = -1; pianoRollH = 422; @@ -260,6 +265,10 @@ int Conf::read() if (!setInt(jRoot, CONF_KEY_BEATS_Y, beatsY)) return 0; if (!setInt(jRoot, CONF_KEY_ABOUT_X, aboutX)) return 0; if (!setInt(jRoot, CONF_KEY_ABOUT_Y, aboutY)) return 0; + if (!setInt(jRoot, CONF_KEY_MIDI_INPUT_X, midiInputX)) return 0; + if (!setInt(jRoot, CONF_KEY_MIDI_INPUT_Y, midiInputY)) return 0; + if (!setInt(jRoot, CONF_KEY_MIDI_INPUT_W, midiInputW)) return 0; + if (!setInt(jRoot, CONF_KEY_MIDI_INPUT_H, midiInputH)) return 0; #ifdef WITH_VST @@ -361,6 +370,10 @@ int Conf::write() json_object_set_new(jRoot, CONF_KEY_BEATS_Y, json_integer(beatsY)); json_object_set_new(jRoot, CONF_KEY_ABOUT_X, json_integer(aboutX)); json_object_set_new(jRoot, CONF_KEY_ABOUT_Y, json_integer(aboutY)); + json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_X, json_integer(midiInputX)); + json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_Y, json_integer(midiInputY)); + json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_W, json_integer(midiInputW)); + json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_H, json_integer(midiInputH)); #ifdef WITH_VST @@ -413,11 +426,19 @@ void Conf::sanitize() if (sampleEditorH < 292) sampleEditorH = 292; if (sampleEditorGridVal < 0) sampleEditorGridVal = 0; if (sampleEditorGridOn < 0) sampleEditorGridOn = 0; + if (midiInputX < 0) midiInputX = 0; + if (midiInputY < 0) midiInputY = 0; + if (midiInputW < G_DEFAULT_MIDI_INPUT_UI_W) midiInputW = G_DEFAULT_MIDI_INPUT_UI_W; + if (midiInputH < G_DEFAULT_MIDI_INPUT_UI_H) midiInputH = G_DEFAULT_MIDI_INPUT_UI_H; if (configX < 0) configX = 0; if (configY < 0) configY = 0; if (pluginListX < 0) pluginListX = 0; if (pluginListY < 0) pluginListY = 0; - if (bpmX < 0) bpmX = 0; +#ifdef WITH_VST + if (pluginChooserW < 640) pluginChooserW = 640; + if (pluginChooserH < 480) pluginChooserW = 480; +#endif + if (bpmX < 0) bpmX = 0; if (bpmY < 0) bpmY = 0; if (beatsX < 0) beatsX = 0; if (beatsY < 0) beatsY = 0; diff --git a/src/core/conf.h b/src/core/conf.h index f96265d..81901bc 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -80,14 +80,14 @@ public: bool limitOutput; int rsmpQuality; - int midiSystem; - int midiPortOut; - int midiPortIn; - bool noNoteOff; - string midiMapPath; - string lastFileMap; - int midiSync; // see const.h - float midiTCfps; + int midiSystem; + int midiPortOut; + int midiPortIn; + bool noNoteOff; + string midiMapPath; + string lastFileMap; + int midiSync; // see const.h + float midiTCfps; uint32_t midiInRewind; uint32_t midiInStartStop; @@ -108,25 +108,27 @@ public: string patchPath; string samplePath; - int mainWindowX, mainWindowY, mainWindowW, mainWindowH; + int mainWindowX, mainWindowY, mainWindowW, mainWindowH; - int browserX, browserY, browserW, browserH, browserPosition, browserLastValue; + int browserX, browserY, browserW, browserH, browserPosition, browserLastValue; string browserLastPath; - int actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom; - int actionEditorGridVal; - int actionEditorGridOn; + int actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom; + int actionEditorGridVal; + int actionEditorGridOn; - int sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH; - int sampleEditorGridVal; - int sampleEditorGridOn; + int sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH; + int sampleEditorGridVal; + int sampleEditorGridOn; - int pianoRollY, pianoRollH; - int pluginListX, pluginListY; - int configX, configY; - int bpmX, bpmY; - int beatsX, beatsY; - int aboutX, aboutY; + int midiInputX, midiInputY, midiInputW, midiInputH; + + int pianoRollY, pianoRollH; + int pluginListX, pluginListY; + int configX, configY; + int bpmX, bpmY; + int beatsX, beatsY; + int aboutX, aboutY; #ifdef WITH_VST diff --git a/src/core/const.h b/src/core/const.h index 9571b2d..99fa701 100644 --- a/src/core/const.h +++ b/src/core/const.h @@ -32,11 +32,11 @@ /* -- version --------------------------------------------------------------- */ -#define G_VERSION_STR "0.13.1" +#define G_VERSION_STR "0.13.2" #define G_APP_NAME "Giada" #define G_VERSION_MAJOR 0 #define G_VERSION_MINOR 13 -#define G_VERSION_PATCH 1 +#define G_VERSION_PATCH 2 #define CONF_FILENAME "giada.conf" @@ -64,17 +64,17 @@ #define GUI_PLUGIN_RATE 0.05 // refresh rate for plugin GUIs #define GUI_FONT_SIZE_BASE 12 -#define COLOR_BD_0 fl_rgb_color(78, 78, 78) // border off +#define COLOR_BD_0 fl_rgb_color(78, 78, 78) // border off - TODO duplicate! #define COLOR_BD_1 fl_rgb_color(188, 188, 188) // border on #define COLOR_BG_0 fl_rgb_color(37, 37, 37) // bg off -#define COLOR_BG_1 fl_rgb_color(78, 78, 78) // bg on (clicked) +#define COLOR_BG_1 fl_rgb_color(78, 78, 78) // bg on (clicked) - TODO duplicate! #define COLOR_BG_2 fl_rgb_color(177, 142, 142) // bg active (play, for some widgets) #define COLOR_BG_3 fl_rgb_color(28, 32, 80) // bg input rec #define COLOR_BG_4 fl_rgb_color(113, 31, 31) // bg action rec #define COLOR_ALERT fl_rgb_color(239, 75, 53) // peak meter alert #define COLOR_TEXT_0 fl_rgb_color(200, 200, 200) -#define COLOR_TEXT_1 fl_rgb_color(25, 25, 25) // TODO - duplicate! -#define COLOR_BG_MAIN fl_rgb_color(25, 25, 25) // windows background +#define COLOR_TEXT_1 fl_rgb_color(25, 25, 25) // TODO duplicate! +#define COLOR_BG_MAIN fl_rgb_color(25, 25, 25) // windows background - TODO duplicate! #define COLOR_BG_RICH fl_rgb_color(30, 30, 30) // lighter background #define COLOR_BG_LINE fl_rgb_color(54, 54, 54) // lighter, for bg lines #define COLOR_BG_DARK fl_rgb_color(0, 0, 0) // inputs background @@ -131,8 +131,8 @@ #define DEFAULT_BUFSIZE 1024 #define DEFAULT_DELAYCOMP 0 #define DEFAULT_VOL 1.0f +#define G_DEFAULT_PITCH 1.0f #define DEFAULT_BOOST 0.0f -#define gDEFAULT_PITCH 1.0f // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only). #define DEFAULT_OUT_VOL 1.0f #define DEFAULT_IN_VOL 1.0f #define DEFAULT_CHANMODE SINGLE_BASIC @@ -143,6 +143,8 @@ #define DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed #define DEFAULT_COLUMN_WIDTH 380 #define G_DEFAULT_PATCH_NAME "(default patch)" +#define G_DEFAULT_MIDI_INPUT_UI_W 300 +#define G_DEFAULT_MIDI_INPUT_UI_H 350 @@ -213,17 +215,6 @@ -/* -- browser types --------------------------------------------------------- */ -/* TODO - USELESS, remove them */ -#define BROWSER_LOAD_PATCH 0x00 -#define BROWSER_LOAD_SAMPLE 0x01 -#define BROWSER_SAVE_PATCH 0x02 -#define BROWSER_SAVE_SAMPLE 0x04 -#define BROWSER_SAVE_PROJECT 0x08 -#define BROWSER_LOAD_PLUGIN 0x10 - - - /* -- channel types --------------------------------------------------------- */ #define CHANNEL_SAMPLE 0x01 #define CHANNEL_MIDI 0x02 @@ -384,6 +375,7 @@ const int MIDI_CHANS[16] = { #define PATCH_KEY_PLUGIN_PATH "path" #define PATCH_KEY_PLUGIN_BYPASS "bypass" #define PATCH_KEY_PLUGIN_PARAMS "params" +#define PATCH_KEY_PLUGIN_MIDI_IN_PARAMS "midi_in_params" #define PATCH_KEY_COLUMN_INDEX "index" #define PATCH_KEY_COLUMN_WIDTH "width" #define PATCH_KEY_COLUMN_CHANNELS "channels" @@ -466,6 +458,10 @@ const int MIDI_CHANS[16] = { #define CONF_KEY_PLUGIN_CHOOSER_Y "plugin_chooser_y" #define CONF_KEY_PLUGIN_CHOOSER_W "plugin_chooser_w" #define CONF_KEY_PLUGIN_CHOOSER_H "plugin_chooser_h" +#define CONF_KEY_MIDI_INPUT_X "midi_input_x" +#define CONF_KEY_MIDI_INPUT_Y "midi_input_y" +#define CONF_KEY_MIDI_INPUT_W "midi_input_w" +#define CONF_KEY_MIDI_INPUT_H "midi_input_h" #define CONF_KEY_PLUGIN_SORT_METHOD "plugin_sort_method" /* JSON midimaps keys */ diff --git a/src/core/init.cpp b/src/core/init.cpp index e280d46..41105a6 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -37,6 +37,7 @@ #include "mixer.h" #include "wave.h" #include "const.h" +#include "channel.h" #include "mixerHandler.h" #include "patch_DEPR_.h" #include "patch.h" @@ -207,6 +208,12 @@ void init_shutdown() } G_Recorder.clearAll(); + for (unsigned i=0; ihasActions = false; + G_Mixer.channels.at(i)->readActions = false; + //if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) + // ((SampleChannel*)G_Mixer.channels.at(i))->readActions = false; + } gu_log("[init] Recorder cleaned up\n"); #ifdef WITH_VST diff --git a/src/core/kernelMidi.cpp b/src/core/kernelMidi.cpp index 9676143..f8c519b 100644 --- a/src/core/kernelMidi.cpp +++ b/src/core/kernelMidi.cpp @@ -39,7 +39,10 @@ #include "midiChannel.h" #include "conf.h" #include "midiMapConf.h" -#include "pluginHost.h" +#ifdef WITH_VST + #include "pluginHost.h" + #include "plugin.h" +#endif #include "kernelMidi.h" @@ -48,8 +51,9 @@ extern Conf G_Conf; extern Mixer G_Mixer; extern KernelMidi G_KernelMidi; extern MidiMapConf G_MidiMap; +#ifdef WITH_VST extern PluginHost G_PluginHost; - +#endif using std::string; using std::vector; @@ -415,7 +419,15 @@ void KernelMidi::processChannels(uint32_t pure, uint32_t value) glue_startStopReadingRecs((SampleChannel*)ch, false); } - /* redirect full midi message to plugins */ +#ifdef WITH_VST + + /* Process plugins' parameters */ + + processPlugins(ch, pure, value); + +#endif + + /* Redirect full midi message (pure + value) to plugins */ ch->receiveMidi(pure | value); } @@ -425,6 +437,37 @@ void KernelMidi::processChannels(uint32_t pure, uint32_t value) /* -------------------------------------------------------------------------- */ +#ifdef WITH_VST + +void KernelMidi::processPlugins(Channel *ch, uint32_t pure, uint32_t value) +{ + /* Plugins' parameters layout reflect the structure of the matrix + Channel::midiInPlugins. It is safe to assume then that i and k indexes match + both the structure of Channel::midiInPlugins and vector *plugins. */ + + vector *plugins = G_PluginHost.getStack(PluginHost::CHANNEL, ch); + + for (unsigned i=0; isize(); i++) + { + Plugin *plugin = plugins->at(i); + for (unsigned k=0; kmidiInParams.size(); k++) { + uint32_t midiInParam = plugin->midiInParams.at(k); + if (pure != midiInParam) + continue; + float vf = (value >> 8)/127.0f; + plugin->setParameter(k, vf); + gu_log(" >>> [plugin %d parameter %d] ch=%d (pure=0x%X, value=%d, float=%f)\n", + i, k, ch->index, pure, value >> 8, vf); + } + } +} + +#endif + + +/* -------------------------------------------------------------------------- */ + + string KernelMidi::getRtMidiVersion() { return midiOut->getVersion(); diff --git a/src/core/kernelMidi.h b/src/core/kernelMidi.h index 834e0de..e8cb0f4 100644 --- a/src/core/kernelMidi.h +++ b/src/core/kernelMidi.h @@ -96,7 +96,7 @@ public: private: - int api; + int api; class RtMidiOut *midiOut; class RtMidiIn *midiIn; @@ -119,6 +119,9 @@ private: void processMaster(uint32_t pure, uint32_t value); void processChannels(uint32_t pure, uint32_t value); +#ifdef WITH_VST + void processPlugins(class Channel *ch, uint32_t pure, uint32_t value); +#endif }; #endif diff --git a/src/core/midiChannel.cpp b/src/core/midiChannel.cpp index cf1f88a..ad531d6 100644 --- a/src/core/midiChannel.cpp +++ b/src/core/midiChannel.cpp @@ -30,19 +30,22 @@ #include "../utils/log.h" #include "midiChannel.h" #include "channel.h" -#include "pluginHost.h" #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "mixer.h" +#ifdef WITH_VST + #include "pluginHost.h" +#endif #include "kernelMidi.h" extern Recorder G_Recorder; extern KernelMidi G_KernelMidi; -extern PluginHost G_PluginHost; extern Mixer G_Mixer; - +#ifdef WITH_VST +extern PluginHost G_PluginHost; +#endif MidiChannel::MidiChannel(int bufferSize, MidiMapConf *midiMapConf) : Channel (CHANNEL_MIDI, STATUS_OFF, bufferSize, midiMapConf), @@ -108,7 +111,7 @@ void MidiChannel::empty() {} /* -------------------------------------------------------------------------- */ -void MidiChannel::quantize(int index, int localFrame, int globalFrame) {} +void MidiChannel::quantize(int index, int localFrame, Mixer *m) {} /* -------------------------------------------------------------------------- */ @@ -335,19 +338,24 @@ void MidiChannel::receiveMidi(uint32_t msg) { if (!armed) return; + +#ifdef WITH_VST + while (true) { if (pthread_mutex_trylock(&G_PluginHost.mutex_midi) != 0) continue; gu_log("[Channel::processMidi] msg=%X\n", msg); -#ifdef WITH_VST addVstMidiEvent(msg, 0); -#endif pthread_mutex_unlock(&G_PluginHost.mutex_midi); break; } - if (G_Recorder.canRec(this)) - G_Recorder.rec(index, ACTION_MIDI, G_Mixer.actualFrame, msg); +#endif + + if (G_Recorder.canRec(this, &G_Mixer)) { + G_Recorder.rec(index, ACTION_MIDI, G_Mixer.currentFrame, msg); + hasActions = true; + } } diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h index dcaaa27..94336b8 100644 --- a/src/core/midiChannel.h +++ b/src/core/midiChannel.h @@ -32,7 +32,7 @@ #ifdef WITH_VST - #include "../deps/juce/config.h" + #include "../deps/juce-config.h" #endif #include "channel.h" @@ -65,7 +65,7 @@ public: int readPatch(const string &basePath, int i, class Patch *patch, pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override; int writePatch(int i, bool isProject, class Patch *patch) override; - void quantize(int index, int localFrame, int globalFrame) override; + void quantize(int index, int localFrame, class Mixer *m) override; void onZero(int frame, bool recsStopOnChanHalt) override; void onBar(int frame) override; void parseAction(Recorder::action *a, int localFrame, int globalFrame, @@ -81,7 +81,6 @@ public: void sendMidi(Recorder::action *a, int localFrame); void sendMidi(uint32_t data); - #ifdef WITH_VST /* addVstMidiEvent diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index 7321f1b..efe2532 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -99,7 +99,7 @@ void Mixer::init() recording = false; ready = true; waitRec = 0; - actualFrame = 0; + currentFrame = 0; bpm = DEFAULT_BPM; bars = DEFAULT_BARS; beats = DEFAULT_BEATS; @@ -246,7 +246,7 @@ Channel *Mixer::getChannelByIndex(int index) void Mixer::sendMIDIsync() { if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { - if (actualFrame % (framesPerBeat/24) == 0) + if (currentFrame % (framesPerBeat/24) == 0) G_KernelMidi.send(MIDI_CLOCK, -1, -1); } else @@ -257,7 +257,7 @@ void Mixer::sendMIDIsync() * 1-4 and 5-8. We check timecode frame's parity: if even, send * range 1-4, if odd send 5-8. */ - if (actualFrame % midiTCrate == 0) { + if (currentFrame % midiTCrate == 0) { /* frame low nibble * frame high nibble @@ -363,7 +363,7 @@ int Mixer::__masterPlay(void *_outBuf, void *_inBuf, unsigned bufferSize) testBar(j); testFirstBeat(j); readActions(j); - actualFrame += 2; + currentFrame += 2; testLastBeat(); // this test must be the last one sendMIDIsync(); } @@ -463,7 +463,7 @@ bool Mixer::isSilent() void Mixer::rewind() { - actualFrame = 0; + currentFrame = 0; actualBeat = 0; if (running) @@ -586,11 +586,11 @@ void Mixer::readActions(unsigned frame) { pthread_mutex_lock(&mutex_recs); for (unsigned i=0; ichan; Channel *ch = getChannelByIndex(index); - ch->parseAction(G_Recorder.global.at(i).at(j), frame, actualFrame, quantize, running); + ch->parseAction(G_Recorder.global.at(i).at(j), frame, currentFrame, quantize, running); } break; } @@ -606,7 +606,7 @@ void Mixer::doQuantize(unsigned frame) { if (quantize < 0 || quanto <= 0) // if quantizer disabled return; - if (actualFrame % (quanto) != 0) // if a quanto has not passed yet + if (currentFrame % (quanto) != 0) // if a quanto has not passed yet return; if (rewindWait) { @@ -615,7 +615,7 @@ void Mixer::doQuantize(unsigned frame) } pthread_mutex_lock(&mutex_chans); for (unsigned i=0; iquantize(i, frame, actualFrame); // j == localFrame + channels.at(i)->quantize(i, frame, this); // j == localFrame pthread_mutex_unlock(&mutex_chans); } @@ -625,7 +625,7 @@ void Mixer::doQuantize(unsigned frame) void Mixer::testBar(unsigned frame) { - if (actualFrame % framesPerBar != 0 || actualFrame == 0) + if (currentFrame % framesPerBar != 0 || currentFrame == 0) return; if (metronome) @@ -643,7 +643,7 @@ void Mixer::testBar(unsigned frame) void Mixer::testFirstBeat(unsigned frame) { - if (actualFrame != 0) + if (currentFrame != 0) return; pthread_mutex_lock(&mutex_chans); for (unsigned k=0; k totalFrames the sequencer returns to frame 0, + /* if currentFrame > totalFrames the sequencer returns to frame 0, * beat 0. This must be the last operation. */ - if (actualFrame > totalFrames) { - actualFrame = 0; + if (currentFrame > totalFrames) { + currentFrame = 0; actualBeat = 0; } else - if (actualFrame % framesPerBeat == 0 && actualFrame > 0) { + if (currentFrame % framesPerBeat == 0 && currentFrame > 0) { actualBeat++; /* avoid tick and tock to overlap when a new bar has passed (which diff --git a/src/core/mixer.h b/src/core/mixer.h index f8afb46..66d0823 100644 --- a/src/core/mixer.h +++ b/src/core/mixer.h @@ -150,7 +150,7 @@ public: int framesPerBeat; // frames in one beat int framesInSequencer; // frames in the whole sequencer int totalFrames; // frames in the selected range (e.g. 4/4) - int actualFrame; + int currentFrame; int actualBeat; #define TICKSIZE 38 diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp index e3d1945..5bb2bd4 100644 --- a/src/core/mixerHandler.cpp +++ b/src/core/mixerHandler.cpp @@ -76,6 +76,7 @@ static int __mh_readPatchPlugins__(vector *list, int type) int ret = 1; for (unsigned i=0; isize(); i++) { Patch::plugin_t *ppl = &list->at(i); + // TODO use glue_addPlugin() Plugin *plugin = G_PluginHost.addPlugin(ppl->path.c_str(), type, &G_Mixer.mutex_plugins, NULL); if (plugin != NULL) { @@ -238,9 +239,9 @@ bool mh_startInputRec() if (channelsReady > 0) { G_Mixer.recording = true; - /* start to write from the actualFrame, not the beginning */ + /* start to write from the currentFrame, not the beginning */ /** FIXME: this should be done before wave allocation */ - G_Mixer.inputTracker = G_Mixer.actualFrame; + G_Mixer.inputTracker = G_Mixer.currentFrame; return true; } return false; diff --git a/src/core/patch.cpp b/src/core/patch.cpp index dbc1aa7..b622537 100644 --- a/src/core/patch.cpp +++ b/src/core/patch.cpp @@ -119,17 +119,23 @@ void Patch::writePlugins(json_t *jContainer, vector *plugins, const ch for (unsigned j=0; jsize(); 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_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(); - for (unsigned z=0; z *container, const c return 0; plugin_t plugin; - if (!setString (jPlugin, PATCH_KEY_PLUGIN_PATH, plugin.path)) return 0; - if (!setBool (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0; + if (!setString(jPlugin, PATCH_KEY_PLUGIN_PATH, plugin.path)) return 0; + if (!setBool (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0; /* read plugin params */ @@ -426,6 +432,16 @@ bool Patch::readPlugins(json_t *jContainer, vector *container, const c 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); + if (!checkArray(jMidiInParams, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS)) return 0; + + size_t midiInParamIndex; + json_t *jMidiInParam; + json_array_foreach(jMidiInParams, midiInParamIndex, jMidiInParam) + plugin.midiInParams.push_back(json_integer_value(jMidiInParam)); + container->push_back(plugin); } return 1; @@ -459,7 +475,7 @@ void Patch::sanitize() ch->panLeft = ch->panLeft < 0.0f || ch->panLeft > 1.0f ? 1.0f : ch->panLeft; ch->panRight = ch->panRight < 0.0f || ch->panRight > 1.0f ? 1.0f : ch->panRight; ch->boost = ch->boost < 1.0f ? DEFAULT_BOOST : ch->boost; - ch->pitch = ch->pitch < 0.1f || ch->pitch > 4.0f ? gDEFAULT_PITCH : ch->pitch; + ch->pitch = ch->pitch < 0.1f || ch->pitch > 4.0f ? G_DEFAULT_PITCH : ch->pitch; } } diff --git a/src/core/patch.h b/src/core/patch.h index 99ef6a1..ba17077 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -56,9 +56,10 @@ public: #ifdef WITH_VST struct plugin_t { - string path; - bool bypass; - vector params; + string path; + bool bypass; + vector params; + vector midiInParams; }; #endif diff --git a/src/core/patch_DEPR_.cpp b/src/core/patch_DEPR_.cpp index 99010a0..5ded87d 100644 --- a/src/core/patch_DEPR_.cpp +++ b/src/core/patch_DEPR_.cpp @@ -31,7 +31,7 @@ #include "../utils/log.h" #include "../utils/fs.h" #include "../gui/dialogs/gd_mainWindow.h" -#include "../gui/elems/ge_keyboard.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" #include "patch_DEPR_.h" #include "init.h" #include "recorder.h" @@ -514,6 +514,7 @@ int Patch_DEPR_::readRecs() G_Recorder.rec(ch->index, type, frame, iValue_fix, fValue); else G_Recorder.rec(ch->index, type, frame, iValue, fValue); + ch->hasActions = true; } } } diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index bf4a1c4..1ef79b2 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -41,24 +41,44 @@ int Plugin::idGenerator = 1; /* -------------------------------------------------------------------------- */ -void Plugin::init() +Plugin::Plugin(juce::AudioPluginInstance *plugin, double samplerate, + int buffersize) + : ui (nullptr), + plugin(plugin), + id (idGenerator++), + bypass(false) { - ui = NULL; - id = idGenerator++;; - bypass = false; - status = 1; + /* Fill midiInParams. All values are empty (0x0): they will be filled during + midi learning process. */ - if (getActiveEditor() != NULL) { - gu_log("[Plugin::init] plugin has an already active editor!\n"); + for (int i=0; igetNumParameters(); i++) + midiInParams.push_back(0x0); + + /* Try to enable editor (i.e. plugin's UI) */ + + if (plugin->getActiveEditor() != NULL) { + gu_log("[Plugin] plugin has an already active editor!\n"); return; } - ui = createEditorIfNeeded(); + ui = plugin->createEditorIfNeeded(); if (ui == NULL) { - gu_log("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n"); + gu_log("[Plugin] unable to create editor, the plugin might be GUI-less!\n"); return; } - gu_log("[Plugin::init] editor initialized and ready\n"); + plugin->prepareToPlay(samplerate, buffersize); + + gu_log("[Plugin] editor initialized and ready\n"); +} + + +/* -------------------------------------------------------------------------- */ + + +Plugin::~Plugin() +{ + plugin->suspendProcessing(true); + plugin->releaseResources(); } @@ -90,7 +110,142 @@ bool Plugin::isEditorOpen() string Plugin::getUniqueId() { - return getPluginDescription().fileOrIdentifier.toStdString(); + return plugin->getPluginDescription().fileOrIdentifier.toStdString(); +} + + +/* -------------------------------------------------------------------------- */ + + +int Plugin::getNumParameters() +{ + return plugin->getNumParameters(); +} + + +/* -------------------------------------------------------------------------- */ + + +float Plugin::getParameter(int paramIndex) +{ + return plugin->getParameter(paramIndex); +} + + +/* -------------------------------------------------------------------------- */ + + +void Plugin::setParameter(int paramIndex, float value) +{ + return plugin->setParameter(paramIndex, value); +} + + +/* -------------------------------------------------------------------------- */ + + +void Plugin::prepareToPlay(double samplerate, int buffersize) +{ + plugin->prepareToPlay(samplerate, buffersize); +} + + +/* -------------------------------------------------------------------------- */ + + +string Plugin::getName() +{ + return plugin->getName().toStdString(); +} + + +/* -------------------------------------------------------------------------- */ + + +bool Plugin::isSuspended() +{ + return plugin->isSuspended(); +} + + +/* -------------------------------------------------------------------------- */ + + +void Plugin::process(juce::AudioBuffer &b, juce::MidiBuffer &m) +{ + plugin->processBlock(b, m); +} + + +/* -------------------------------------------------------------------------- */ + + +int Plugin::getNumPrograms() +{ + return plugin->getNumPrograms(); +} + + +/* -------------------------------------------------------------------------- */ + + +int Plugin::getCurrentProgram() +{ + return plugin->getCurrentProgram(); +} + + +/* -------------------------------------------------------------------------- */ + + +void Plugin::setCurrentProgram(int index) +{ + plugin->setCurrentProgram(index); +} + + +/* -------------------------------------------------------------------------- */ + + +bool Plugin::hasEditor() +{ + return plugin->hasEditor(); +} + + +/* -------------------------------------------------------------------------- */ + + +string Plugin::getProgramName(int index) +{ + return plugin->getProgramName(index).toStdString(); +} + + +/* -------------------------------------------------------------------------- */ + + +string Plugin::getParameterName(int index) +{ + return plugin->getParameterName(index).toStdString(); +} + + +/* -------------------------------------------------------------------------- */ + + +string Plugin::getParameterText(int index) +{ + return plugin->getParameterText(index).toStdString(); +} + + +/* -------------------------------------------------------------------------- */ + + +string Plugin::getParameterLabel(int index) +{ + return plugin->getParameterLabel(index).toStdString(); } diff --git a/src/core/plugin.h b/src/core/plugin.h index 38e411c..d295e50 100644 --- a/src/core/plugin.h +++ b/src/core/plugin.h @@ -26,32 +26,32 @@ * * -------------------------------------------------------------------------- */ + #ifdef WITH_VST #ifndef __PLUGIN_H__ #define __PLUGIN_H__ -#include "../deps/juce/config.h" - +#include "../deps/juce-config.h" -using std::string; - -class Plugin : public juce::AudioPluginInstance +class Plugin { private: + static int idGenerator; + juce::AudioProcessorEditor *ui; // gui + juce::AudioPluginInstance *plugin; // core - static int idGenerator; - int id; - bool bypass; - bool status; + int id; + bool bypass; public: - void init(); + Plugin(juce::AudioPluginInstance *p, double samplerate, int buffersize); + ~Plugin(); void showEditor(void *parent); @@ -67,16 +67,36 @@ public: /* getUniqueId * Return a string-based UID. */ - string getUniqueId(); + std::string getUniqueId(); + + std::string getName(); + + bool hasEditor(); + int getNumParameters(); + float getParameter(int index); + void setParameter(int index, float value); + std::string getParameterName(int index); + std::string getParameterText(int index); + std::string getParameterLabel(int index); + void prepareToPlay(double samplerate, int buffersize); + bool isSuspended(); + void process(juce::AudioBuffer &b, juce::MidiBuffer &m); + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram(int index); + std::string getProgramName(int index); int getId() { return id; } - bool getStatus() { return status; } bool isBypassed() { return bypass; } int getEditorW() { return ui->getWidth(); } int getEditorH() { return ui->getHeight(); } void toggleBypass() { bypass = !bypass; } - void setStatus(int s) { status = s; } void setBypass(bool b) { bypass = b; } + + /* midiInParams + A list of midiIn hex values for parameter automation. */ + + std::vector midiInParams; }; #endif diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp index f95a966..a23f266 100644 --- a/src/core/pluginHost.cpp +++ b/src/core/pluginHost.cpp @@ -144,35 +144,28 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, return NULL; } - Plugin *p = (Plugin *) pluginFormat.createInstanceFromDescription(*pd, samplerate, buffersize); - if (!p) { + juce::AudioPluginInstance *pi = pluginFormat.createInstanceFromDescription(*pd, samplerate, buffersize); + if (!pi) { gu_log("[PluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str()); missingPlugins = true; return NULL; } - - //p->setStatus(1); - //p->setId(); - //p->initEditor(); - p->init(); - p->prepareToPlay(samplerate, buffersize); - gu_log("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str()); + Plugin *p = new Plugin(pi, samplerate, buffersize); + /* Try to inject the plugin as soon as possible. */ - int lockStatus; while (true) { - lockStatus = pthread_mutex_trylock(mutex); - if (lockStatus == 0) { - pStack->push_back(p); - pthread_mutex_unlock(mutex); - break; - } + if (pthread_mutex_trylock(mutex) != 0) + continue; + pStack->push_back(p); + pthread_mutex_unlock(mutex); + break; } gu_log("[PluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n", - fid.c_str(), p->getName().toStdString().c_str(), stackType, pStack->size()); + fid.c_str(), p->getName().c_str(), stackType, pStack->size()); return p; } @@ -286,22 +279,14 @@ void PluginHost::freeStack(int stackType, pthread_mutex_t *mutex, Channel *ch) if (pStack->size() == 0) return; - int lockStatus; while (true) { - lockStatus = pthread_mutex_trylock(mutex); - if (lockStatus == 0) { - for (unsigned i=0; isize(); i++) { - Plugin *pPlugin = pStack->at(i); - if (pPlugin->getStatus() != 0) { // take care if plugin is in good status - pPlugin->suspendProcessing(true); - pPlugin->releaseResources(); - } - delete pPlugin; - } - pStack->clear(); - pthread_mutex_unlock(mutex); - break; - } + if (pthread_mutex_trylock(mutex) != 0) + continue; + for (unsigned i=0; isize(); i++) + delete pStack->at(i); + pStack->clear(); + pthread_mutex_unlock(mutex); + break; } gu_log("[PluginHost::freeStack] stack type=%d freed\n", stackType); } @@ -337,17 +322,17 @@ void PluginHost::processStack(float *buffer, int stackType, Channel *ch) for (unsigned i=0; isize(); i++) { Plugin *plugin = pStack->at(i); - if (plugin->getStatus() != 1 || plugin->isSuspended() || plugin->isBypassed()) + if (plugin->isSuspended() || plugin->isBypassed()) continue; if (ch) { // ch might be null if stackType is MASTER_IN/OUT pthread_mutex_lock(&mutex_midi); - plugin->processBlock(audioBuffer, ch->getPluginMidiEvents()); + plugin->process(audioBuffer, ch->getPluginMidiEvents()); ch->clearMidiBuffer(); pthread_mutex_unlock(&mutex_midi); } else { juce::MidiBuffer midiBuffer; // empty buffer - plugin->processBlock(audioBuffer, midiBuffer); + plugin->process(audioBuffer, midiBuffer); } } @@ -395,17 +380,13 @@ void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, pthread_mutex_t *mutex, Channel *ch) { vector *pStack = getStack(stackType, ch); - int lockStatus; while (true) { - lockStatus = pthread_mutex_trylock(mutex); - if (lockStatus == 0) { - std::swap(pStack->at(indexA), pStack->at(indexB)); - pthread_mutex_unlock(mutex); - gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB); - return; - } - //else - //gu_log("[pluginHost] waiting for mutex...\n"); + if (pthread_mutex_trylock(mutex) != 0) + continue; + std::swap(pStack->at(indexA), pStack->at(indexB)); + pthread_mutex_unlock(mutex); + gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB); + return; } } @@ -413,35 +394,26 @@ void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, /* -------------------------------------------------------------------------- */ -void PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex, +int PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex, Channel *ch) { vector *pStack = getStack(stackType, ch); - for (unsigned i=0; isize(); i++) { Plugin *pPlugin = pStack->at(i); if (pPlugin->getId() != id) continue; - if (pPlugin->getStatus() == 0) { // no frills if plugin is missing - delete pPlugin; - pStack->erase(pStack->begin() + i); - gu_log("[pluginHost::freePlugin] plugin id=%d removed with no frills, since it had status=0\n", id); - return; - } - while (true) { if (pthread_mutex_trylock(mutex) != 0) continue; - pPlugin->suspendProcessing(true); - pPlugin->releaseResources(); delete pPlugin; pStack->erase(pStack->begin() + i); pthread_mutex_unlock(mutex); gu_log("[pluginHost::freePlugin] plugin id=%d removed\n", id); - return; + return i; } } gu_log("[pluginHost::freePlugin] plugin id=%d not found\n", id); + return -1; } @@ -475,15 +447,15 @@ void PluginHost::freeAllStacks(vector *channels, pthread_mutex_t *mut int PluginHost::clonePlugin(Plugin *src, int stackType, pthread_mutex_t *mutex, Channel *ch) { - juce::PluginDescription pd = src->getPluginDescription(); - Plugin *p = addPlugin(pd.fileOrIdentifier.toStdString(), stackType, mutex, ch); + Plugin *p = addPlugin(src->getUniqueId(), stackType, mutex, ch); if (!p) { gu_log("[PluginHost::clonePlugin] unable to add new plugin to stack!\n"); return 0; } - for (int k=0; kgetNumParameters(); k++) { + + for (int k=0; kgetNumParameters(); k++) p->setParameter(k, src->getParameter(k)); - } + return 1; } diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h index c1f0a51..2ddc7a5 100644 --- a/src/core/pluginHost.h +++ b/src/core/pluginHost.h @@ -33,7 +33,7 @@ #include -#include "../deps/juce/config.h" +#include "../deps/juce-config.h" using std::string; @@ -186,19 +186,19 @@ public: void swapPlugin(unsigned indexA, unsigned indexB, int stackType, pthread_mutex_t *mutex, class Channel *ch=NULL); - /* freePlugin */ + /* freePlugin. + Returns the internal stack index of the deleted plugin. */ - void freePlugin(int id, int stackType, pthread_mutex_t *mutex, + int freePlugin(int id, int stackType, pthread_mutex_t *mutex, class Channel *ch=NULL); - /* runDispatchLoop - * Wake up plugins' GUI manager for N milliseconds. */ + * Wakes up plugins' GUI manager for N milliseconds. */ void runDispatchLoop(); /* freeAllStacks - * Free everything. */ + * Frees everything. */ void freeAllStacks(vector *channels, pthread_mutex_t *mutex); diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index 57958c7..992a98e 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -29,23 +29,12 @@ #include #include "../utils/log.h" -#include "../utils/fs.h" -#include "const.h" #include "mixer.h" -#include "mixerHandler.h" -#include "kernelAudio.h" -#include "kernelMidi.h" #include "patch_DEPR_.h" -#include "conf.h" -#include "channel.h" #include "sampleChannel.h" #include "recorder.h" -extern KernelAudio G_KernelAudio; -extern Mixer G_Mixer; - - Recorder::Recorder() : active (false), sortedActions(false) @@ -66,7 +55,7 @@ void Recorder::init() /* -------------------------------------------------------------------------- */ -bool Recorder::canRec(Channel *ch) +bool Recorder::canRec(Channel *ch, Mixer *mixer) { /* NO recording if: * recorder is inactive @@ -74,9 +63,9 @@ bool Recorder::canRec(Channel *ch) * mixer is recording a take somewhere * channel is empty */ - if (!active || - !G_Mixer.running || - G_Mixer.recording || + if (!active || + !mixer->running || + mixer->recording || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL) ) return false; @@ -142,11 +131,6 @@ void Recorder::rec(int index, int type, int frame, uint32_t iValue, float fValue global.at(frameToExpand).push_back(a); // expand array } - /* don't activate the channel (readActions == false), it's up to - * the other layers */ - - G_Mixer.getChannelByIndex(index)->hasActions = true; - sortedActions = false; gu_log("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (0x%X) fValue=%f\n", @@ -175,9 +159,6 @@ void Recorder::clearChan(int index) j++; } } - - Channel *ch = G_Mixer.getChannelByIndex(index); - ch->hasActions = false; optimize(); //print(); } @@ -203,10 +184,7 @@ void Recorder::clearAction(int index, char act) j++; } } - Channel *ch = G_Mixer.getChannelByIndex(index); - ch->hasActions = false; /// FIXME - why this? Isn't it useless if we call setChanHasActionsStatus? optimize(); - setChanHasActionsStatus(index); /// FIXME //print(); } @@ -215,7 +193,7 @@ void Recorder::clearAction(int index, char act) void Recorder::deleteAction(int chan, int frame, char type, bool checkValues, - uint32_t iValue, float fValue) + pthread_mutex_t *mixerMutex, uint32_t iValue, float fValue) { /* make sure frame is even */ @@ -226,41 +204,39 @@ void Recorder::deleteAction(int chan, int frame, char type, bool checkValues, bool found = false; for (unsigned i=0; ichan == chan && a->type == (type & a->type)); - if (checkValues) - doit &= (a->iValue == iValue && a->fValue == fValue); - - if (doit) { - // TODO - wft? just do: while (true); if (pthread_mutex_trylock(&G_Mixer.mutex_recs)) - int lockStatus = 0; - while (lockStatus == 0) { - lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs); - if (lockStatus == 0) { - free(a); - global.at(i).erase(global.at(i).begin() + j); - pthread_mutex_unlock(&G_Mixer.mutex_recs); - found = true; - break; - } - else - gu_log("[REC] delete action: waiting for mutex...\n"); - } - } - } + for (unsigned j=0; jchan == chan && a->type == (type & a->type)); + if (checkValues) + doit &= (a->iValue == iValue && a->fValue == fValue); + + if (!doit) + continue; + + while (true) { + if (pthread_mutex_trylock(mixerMutex)) { + free(a); + global.at(i).erase(global.at(i).begin() + j); + pthread_mutex_unlock(mixerMutex); + found = true; + break; + } + else + gu_log("[REC] delete action: waiting for mutex...\n"); + } } } if (found) { optimize(); - setChanHasActionsStatus(chan); gu_log("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } @@ -273,7 +249,8 @@ void Recorder::deleteAction(int chan, int frame, char type, bool checkValues, /* -------------------------------------------------------------------------- */ -void Recorder::deleteActions(int chan, int frame_a, int frame_b, char type) +void Recorder::deleteActions(int chan, int frame_a, int frame_b, char type, + pthread_mutex_t *mixerMutex) { sortActions(); vector dels; @@ -283,7 +260,7 @@ void Recorder::deleteActions(int chan, int frame_a, int frame_b, char type) dels.push_back(frames.at(i)); for (unsigned i=0; ihasActions = false; - if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) - ((SampleChannel*)G_Mixer.channels.at(i))->readActions = false; - } - global.clear(); frames.clear(); } @@ -494,22 +464,17 @@ void Recorder::shrink(int new_fpb) /* -------------------------------------------------------------------------- */ -void Recorder::setChanHasActionsStatus(int index) +bool Recorder::hasActions(int chanIndex) { - Channel *ch = G_Mixer.getChannelByIndex(index); - if (global.size() == 0) { - ch->hasActions = false; - return; - } + if (global.size() == 0) + return false; for (unsigned i=0; ichan == index) { - ch->hasActions = true; - return; - } + if (global.at(i).at(j)->chan == chanIndex) + return true; } } - ch->hasActions = false; + return false; } @@ -564,7 +529,8 @@ int Recorder::getAction(int chan, char action, int frame, struct action **out) /* -------------------------------------------------------------------------- */ -void Recorder::startOverdub(int index, char actionMask, int frame) +void Recorder::startOverdub(int index, char actionMask, int frame, + unsigned bufferSize) { /* prepare the composite struct */ @@ -590,25 +556,22 @@ void Recorder::startOverdub(int index, char actionMask, int frame) int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act); if (res == 1) { if (act->type == cmp.a2.type) { - int truncFrame = cmp.a1.frame - G_KernelAudio.realBufsize; + int truncFrame = cmp.a1.frame - bufferSize; if (truncFrame < 0) truncFrame = 0; gu_log("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type); rec(index, cmp.a2.type, truncFrame); } } - - SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(index); - ch->readActions = false; // don't use disableRead() } /* -------------------------------------------------------------------------- */ -void Recorder::stopOverdub(int frame) +void Recorder::stopOverdub(Mixer *mixer) { - cmp.a2.frame = frame; + cmp.a2.frame = mixer->currentFrame; bool ringLoop = false; bool nullLoop = false; @@ -618,23 +581,20 @@ void Recorder::stopOverdub(int frame) if (cmp.a2.frame < cmp.a1.frame) { ringLoop = true; gu_log("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame); - rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames); // record at the end of the sequencer + rec(cmp.a2.chan, cmp.a2.type, mixer->totalFrames); // record at the end of the sequencer } else if (cmp.a2.frame == cmp.a1.frame) { nullLoop = true; gu_log("[REC] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame); - deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values + deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false, &mixer->mutex_recs); // false == don't check values } - SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(cmp.a2.chan); - ch->readActions = false; // don't use disableRead() - /* remove any nested action between keypress----keyrel, then record */ if (!nullLoop) { - deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type); - deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type); + deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type, &mixer->mutex_recs); + deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type, &mixer->mutex_recs); } if (!ringLoop && !nullLoop) { @@ -645,11 +605,9 @@ void Recorder::stopOverdub(int frame) action *act = NULL; int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act); - if (res == 1) { - if (act->type == cmp.a2.type) { - gu_log("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type); - deleteAction(act->chan, act->frame, act->type, false); // false == don't check values - } + if (res == 1 && act->type == cmp.a2.type) { + gu_log("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type); + deleteAction(act->chan, act->frame, act->type, false, &mixer->mutex_recs); // false == don't check values } } } @@ -664,7 +622,8 @@ void Recorder::print() for (unsigned i=0; itype, global.at(i).at(j)->chan, global.at(i).at(j)->frame); + gu_log(" action %d | chan %d | frame %d\n", global.at(i).at(j)->type, + global.at(i).at(j)->chan, global.at(i).at(j)->frame); } } } diff --git a/src/core/recorder.h b/src/core/recorder.h index 307b408..a4f0210 100644 --- a/src/core/recorder.h +++ b/src/core/recorder.h @@ -37,6 +37,7 @@ #include #endif #include +#include using std::vector; @@ -79,16 +80,16 @@ public: void init(); - /* setChanHasActionsStatus - * Check if the channel has at least one action recorded. If false, sets - * ch->hasActions = false. Used after an action deletion. */ + /* hasActions + Checks if the channel has at least one action recorded. Used after an + action deletion. */ - void setChanHasActionsStatus(int chan); + bool hasActions(int chanIndex); /* canRec * can a channel rec an action? Call this one BEFORE rec(). */ - bool canRec(class Channel *ch); + bool canRec(class Channel *ch, class Mixer *m); /* rec * record an action. */ @@ -110,13 +111,14 @@ public: * delete ONE action. Useful in the action editor. 'type' can be a mask. */ void deleteAction(int chan, int frame, char type, bool checkValues, - uint32_t iValue=0, float fValue=0.0); + pthread_mutex_t *mixerMutex, uint32_t iValue=0, float fValue=0.0); /* deleteActions * delete A RANGE of actions from frame_a to frame_b in channel 'chan'. * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */ - void deleteActions(int chan, int frame_a, int frame_b, char type); + void deleteActions(int chan, int frame_a, int frame_b, char type, + pthread_mutex_t *mixerMutex); /* clearAll * delete everything. */ @@ -164,8 +166,8 @@ public: /* start/endOverdub */ - void startOverdub(int chan, char action, int frame); - void stopOverdub(int frame); + void startOverdub(int chan, char action, int frame, unsigned bufferSize); + void stopOverdub(class Mixer *m); private: diff --git a/src/core/sampleChannel.cpp b/src/core/sampleChannel.cpp index 4489801..650d36f 100644 --- a/src/core/sampleChannel.cpp +++ b/src/core/sampleChannel.cpp @@ -34,6 +34,7 @@ #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" +#include "mixer.h" #include "wave.h" #include "pluginHost.h" #include "waveFx.h" @@ -56,7 +57,7 @@ SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf) tracker (0), begin (0), end (0), - pitch (gDEFAULT_PITCH), + pitch (G_DEFAULT_PITCH), boost (1.0f), mode (DEFAULT_CHANMODE), qWait (false), @@ -66,7 +67,6 @@ SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf) fadeoutVol (1.0f), fadeoutTracker (0), fadeoutStep (DEFAULT_FADEOUT_STEP), - readActions (false), midiInReadActions(0x0), midiInPitch (0x0) { @@ -477,7 +477,7 @@ void SampleChannel::onZero(int frame, bool recsStopOnChanHalt) /* -------------------------------------------------------------------------- */ -void SampleChannel::quantize(int index, int localFrame, int globalFrame) +void SampleChannel::quantize(int index, int localFrame, Mixer *mixer) { /* skip if LOOP_ANY or not in quantizer-wait mode */ @@ -500,11 +500,15 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) /* this is the moment in which we record the keypress, if the * quantizer is on. SINGLE_PRESS needs overdub */ - if (G_Recorder.canRec(this)) { - if (mode == SINGLE_PRESS) - G_Recorder.startOverdub(index, ACTION_KEYS, globalFrame); + if (G_Recorder.canRec(this, mixer)) { + if (mode == SINGLE_PRESS) { + G_Recorder.startOverdub(index, ACTION_KEYS, mixer->currentFrame, + G_KernelAudio.realBufsize); + readActions = false; // don't read actions while overdubbing + } else - G_Recorder.rec(index, ACTION_KEYPRESS, globalFrame); + G_Recorder.rec(index, ACTION_KEYPRESS, mixer->currentFrame); + hasActions = true; } } diff --git a/src/core/sampleChannel.h b/src/core/sampleChannel.h index 751b999..2eeb574 100644 --- a/src/core/sampleChannel.h +++ b/src/core/sampleChannel.h @@ -106,7 +106,7 @@ public: int readPatch(const string &basePath, int i, class Patch *patch, pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override; int writePatch(int i, bool isProject, class Patch *patch) override; - void quantize(int index, int localFrame, int globalFrame) override; + void quantize(int index, int localFrame, class Mixer *m) override; void onZero(int frame, bool recsStopOnChanHalt) override; void onBar(int frame) override; void parseAction(Recorder::action *a, int localFrame, int globalFrame, @@ -193,10 +193,6 @@ public: int fadeoutType; // xfade or fadeout int fadeoutEnd; // what to do when fadeout ends - /* recorder:: stuff */ - - bool readActions; // read actions or not - /* midi stuff */ uint32_t midiInReadActions; diff --git a/src/deps/juce-config.h b/src/deps/juce-config.h new file mode 100644 index 0000000..ea20a6c --- /dev/null +++ b/src/deps/juce-config.h @@ -0,0 +1,21 @@ +#ifndef __JUCE_APPCONFIG_H__ +#define __JUCE_APPCONFIG_H__ + + +#ifdef _WIN32 + #include + #include +#endif + + +#include "juce/modules/juce_audio_basics/juce_audio_basics.h" +#include "juce/modules/juce_audio_processors/juce_audio_processors.h" +#include "juce/modules/juce_core/juce_core.h" +#include "juce/modules/juce_data_structures/juce_data_structures.h" +#include "juce/modules/juce_events/juce_events.h" +#include "juce/modules/juce_graphics/juce_graphics.h" +#include "juce/modules/juce_gui_basics/juce_gui_basics.h" +#include "juce/modules/juce_gui_extra/juce_gui_extra.h" + + +#endif diff --git a/src/glue/channel.cpp b/src/glue/channel.cpp index c1fa9ba..0af1044 100644 --- a/src/glue/channel.cpp +++ b/src/glue/channel.cpp @@ -30,10 +30,11 @@ #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_editor.h" -#include "../gui/elems/ge_keyboard.h" #include "../gui/elems/ge_waveTools.h" #include "../gui/elems/ge_waveform.h" -#include "../gui/elems/channel.h" +#include "../gui/elems/ge_mixed.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" +#include "../gui/elems/mainWindow/keyboard/channel.h" #include "../utils/gui.h" #include "../core/mixerHandler.h" #include "../core/mixer.h" @@ -43,16 +44,18 @@ #include "../core/channel.h" #include "../core/sampleChannel.h" #include "../core/midiChannel.h" +#include "../core/plugin.h" #include "main.h" #include "channel.h" extern gdMainWindow *G_MainWin; extern Conf G_Conf; +extern KernelAudio G_KernelAudio; extern Recorder G_Recorder; extern Mixer G_Mixer; #ifdef WITH_VST -extern PluginHost G_PluginHost; +extern PluginHost G_PluginHost; #endif @@ -101,6 +104,7 @@ Channel *glue_addChannel(int column, int type) void glue_deleteChannel(Channel *ch) { G_Recorder.clearChan(ch->index); + ch->hasActions = false; #ifdef WITH_VST G_PluginHost.freeStack(PluginHost::CHANNEL, &G_Mixer.mutex_plugins, ch); #endif @@ -125,6 +129,7 @@ void glue_freeChannel(Channel *ch) #endif G_MainWin->keyboard->freeChannel(ch->guiChannel); G_Recorder.clearChan(ch->index); + ch->hasActions = false; ch->empty(); } @@ -243,11 +248,14 @@ void glue_setPanning(gdEditor *win, SampleChannel *ch, float val) void glue_setMute(Channel *ch, bool gui) { - if (G_Recorder.active && G_Recorder.canRec(ch)) { - if (!ch->mute) - G_Recorder.startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame); + if (G_Recorder.active && G_Recorder.canRec(ch, &G_Mixer)) { + if (!ch->mute) { + G_Recorder.startOverdub(ch->index, ACTION_MUTES, G_Mixer.currentFrame, + G_KernelAudio.realBufsize); + ch->readActions = false; // don't read actions while overdubbing + } else - G_Recorder.stopOverdub(G_Mixer.actualFrame); + G_Recorder.stopOverdub(&G_Mixer); } ch->mute ? ch->unsetMute(false) : ch->setMute(false); @@ -434,8 +442,7 @@ void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric) /* -------------------------------------------------------------------------- */ -void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, - bool numeric) +void glue_setVolEditor(gdEditor *win, SampleChannel *ch, float val, bool numeric) { if (numeric) { if (val > 0.0f) diff --git a/src/glue/channel.h b/src/glue/channel.h index 25523e0..3534add 100644 --- a/src/glue/channel.h +++ b/src/glue/channel.h @@ -94,4 +94,5 @@ void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); + #endif diff --git a/src/glue/io.cpp b/src/glue/io.cpp index bdc932e..4dc9acf 100644 --- a/src/glue/io.cpp +++ b/src/glue/io.cpp @@ -35,9 +35,11 @@ #include #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_warnings.h" -#include "../gui/elems/ge_keyboard.h" -#include "../gui/elems/channel.h" -#include "../gui/elems/sampleChannel.h" +#include "../gui/elems/mainWindow/mainTransport.h" +#include "../gui/elems/mainWindow/mainTimer.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" +#include "../gui/elems/mainWindow/keyboard/channel.h" +#include "../gui/elems/mainWindow/keyboard/sampleChannel.h" #include "../utils/gui.h" #include "../utils/log.h" #include "../core/recorder.h" @@ -53,6 +55,7 @@ extern Recorder G_Recorder; +extern KernelAudio G_KernelAudio; extern bool G_audio_status; extern Mixer G_Mixer; extern gdMainWindow *G_MainWin; @@ -117,8 +120,10 @@ void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift) if (G_Recorder.active) { if (G_Mixer.running) { ch->kill(0); // on frame 0: user-generated event - if (G_Recorder.canRec(ch) && !(ch->mode & LOOP_ANY)) // don't record killChan actions for LOOP channels - G_Recorder.rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame); + if (G_Recorder.canRec(ch, &G_Mixer) && !(ch->mode & LOOP_ANY)) { // don't record killChan actions for LOOP channels + G_Recorder.rec(ch->index, ACTION_KILLCHAN, G_Mixer.currentFrame); + ch->hasActions = true; + } } } else { @@ -138,14 +143,18 @@ void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift) * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are * meaningless for loop modes */ - if (G_Mixer.quantize == 0 && - G_Recorder.canRec(ch) && + if (G_Mixer.quantize == 0 && + G_Recorder.canRec(ch, &G_Mixer) && !(ch->mode & LOOP_ANY)) { - if (ch->mode == SINGLE_PRESS) - G_Recorder.startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame); + if (ch->mode == SINGLE_PRESS) { + G_Recorder.startOverdub(ch->index, ACTION_KEYS, G_Mixer.currentFrame, + G_KernelAudio.realBufsize); + ch->readActions = false; // don't read actions while overdubbing + } else { - G_Recorder.rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame); + G_Recorder.rec(ch->index, ACTION_KEYPRESS, G_Mixer.currentFrame); + ch->hasActions = true; /* Why return here? You record an action (as done on line 148) and then you call ch->start (line 165): Mixer, which is on another thread, reads @@ -182,8 +191,8 @@ void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift) /* record a key release only if channel is single_press. For any * other mode the KEY REL is meaningless. */ - if (ch->mode == SINGLE_PRESS && G_Recorder.canRec(ch)) - G_Recorder.stopOverdub(G_Mixer.actualFrame); + if (ch->mode == SINGLE_PRESS && G_Recorder.canRec(ch, &G_Mixer)) + G_Recorder.stopOverdub(&G_Mixer); /* the GUI update is done by gui_refresh() */ @@ -214,7 +223,7 @@ void glue_startActionRec(bool gui) if (!gui) { Fl::lock(); - G_MainWin->controller->updateRecAction(1); + G_MainWin->mainTransport->updateRecAction(1); Fl::unlock(); } } @@ -242,7 +251,7 @@ void glue_stopActionRec(bool gui) if (!gui) { Fl::lock(); - G_MainWin->controller->updateRecAction(0); + G_MainWin->mainTransport->updateRecAction(0); Fl::unlock(); } @@ -273,7 +282,7 @@ int glue_startInputRec(bool gui) if (!mh_startInputRec()) { Fl::lock(); - G_MainWin->controller->updateRecInput(0); // set it off, anyway + G_MainWin->mainTransport->updateRecInput(0); // set it off, anyway Fl::unlock(); return false; } @@ -281,11 +290,11 @@ int glue_startInputRec(bool gui) if (!G_Mixer.running) glue_startSeq(false); // update gui anyway - if (!gui) { - Fl::lock(); - G_MainWin->controller->updateRecInput(1); - Fl::unlock(); - } + Fl::lock(); + if (!gui) + G_MainWin->mainTransport->updateRecInput(1); + G_MainWin->mainTimer->setLock(true); + Fl::unlock(); /* Update sample name inside sample channels' main button. This is useless for midi channel, but let's do it anyway. */ @@ -314,14 +323,14 @@ int glue_stopInputRec(bool gui) continue; SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->armed) - ch->start(G_Mixer.actualFrame, true, G_Mixer.quantize, G_Mixer.running, true, true); + ch->start(G_Mixer.currentFrame, true, G_Mixer.quantize, G_Mixer.running, true, true); } - if (!gui) { - Fl::lock(); - G_MainWin->controller->updateRecInput(0); - Fl::unlock(); - } + Fl::lock(); + if (!gui) + G_MainWin->mainTransport->updateRecInput(0); + G_MainWin->mainTimer->setLock(false); + Fl::unlock(); return 1; } diff --git a/src/glue/main.cpp b/src/glue/main.cpp index 4c3638f..d9033d0 100644 --- a/src/glue/main.cpp +++ b/src/glue/main.cpp @@ -35,10 +35,13 @@ #include #include "../gui/elems/ge_waveform.h" #include "../gui/elems/ge_mixed.h" -#include "../gui/elems/channel.h" -#include "../gui/elems/sampleChannel.h" #include "../gui/elems/ge_waveTools.h" -#include "../gui/elems/ge_keyboard.h" +#include "../gui/elems/mainWindow/mainTransport.h" +#include "../gui/elems/mainWindow/mainIO.h" +#include "../gui/elems/mainWindow/mainTimer.h" +#include "../gui/elems/mainWindow/keyboard/channel.h" +#include "../gui/elems/mainWindow/keyboard/sampleChannel.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_editor.h" #include "../gui/dialogs/gd_warnings.h" @@ -74,6 +77,11 @@ extern PluginHost G_PluginHost; void glue_setBpm(const char *v1, const char *v2) { + /* Never change this stuff while recording audio */ + + if (G_Mixer.recording) + return; + char buf[6]; float value = atof(v1) + (atof(v2)/10); if (value < 20.0f) { @@ -96,7 +104,7 @@ void glue_setBpm(const char *v1, const char *v2) G_Recorder.updateBpm(old_bpm, value, G_Mixer.quanto); gu_refreshActionEditor(); - G_MainWin->timing->setBpm(buf); + G_MainWin->mainTimer->setBpm(buf); gu_log("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm); } @@ -106,7 +114,12 @@ void glue_setBpm(const char *v1, const char *v2) void glue_setBeats(int beats, int bars, bool expand) { - /* temp vars to store old data (they are necessary) */ + /* Never change this stuff while recording audio */ + + if (G_Mixer.recording) + return; + + /* Temp vars to store old data (they are necessary) */ int oldvalue = G_Mixer.beats; unsigned oldfpb = G_Mixer.totalFrames; @@ -145,7 +158,7 @@ void glue_setBeats(int beats, int bars, bool expand) // G_Recorder.shrink(G_Mixer.totalFrames); } - G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); + G_MainWin->mainTimer->setMeter(G_Mixer.beats, G_Mixer.bars); gu_refreshActionEditor(); // in case the action editor is open } @@ -179,7 +192,7 @@ void glue_startSeq(bool gui) if (!gui) { Fl::lock(); - G_MainWin->controller->updatePlay(1); + G_MainWin->mainTransport->updatePlay(1); Fl::unlock(); } } @@ -206,7 +219,7 @@ void glue_stopSeq(bool gui) if (G_Recorder.active) { G_Recorder.active = false; Fl::lock(); - G_MainWin->controller->updateRecAction(0); + G_MainWin->mainTransport->updateRecAction(0); Fl::unlock(); } @@ -216,13 +229,13 @@ void glue_stopSeq(bool gui) if (G_Mixer.recording) { mh_stopInputRec(); Fl::lock(); - G_MainWin->controller->updateRecInput(0); + G_MainWin->mainTransport->updateRecInput(0); Fl::unlock(); } if (!gui) { Fl::lock(); - G_MainWin->controller->updatePlay(0); + G_MainWin->mainTransport->updatePlay(0); Fl::unlock(); } } @@ -321,7 +334,7 @@ void glue_setOutVol(float v, bool gui) G_Mixer.outVol = v; if (!gui) { Fl::lock(); - G_MainWin->inOut->setOutVol(v); + G_MainWin->mainIO->setOutVol(v); Fl::unlock(); } } @@ -335,7 +348,7 @@ void glue_setInVol(float v, bool gui) G_Mixer.inVol = v; if (!gui) { Fl::lock(); - G_MainWin->inOut->setInVol(v); + G_MainWin->mainIO->setInVol(v); Fl::unlock(); } } @@ -398,7 +411,7 @@ void glue_startStopMetronome(bool gui) G_Mixer.metronome = !G_Mixer.metronome; if (!gui) { Fl::lock(); - G_MainWin->controller->updateMetronome(G_Mixer.metronome); + G_MainWin->mainTransport->updateMetronome(G_Mixer.metronome); Fl::unlock(); } } diff --git a/src/glue/plugin.cpp b/src/glue/plugin.cpp new file mode 100644 index 0000000..8c4ee23 --- /dev/null +++ b/src/glue/plugin.cpp @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST + + +#include "../core/pluginHost.h" +#include "../core/mixer.h" +#include "../core/plugin.h" +#include "../core/channel.h" +#include "plugin.h" + + +extern Mixer G_Mixer; +extern PluginHost G_PluginHost; + + +Plugin *glue_addPlugin(Channel *ch, int index, int stackType) +{ + if (index >= G_PluginHost.countAvailablePlugins()) + return nullptr; + + return G_PluginHost.addPlugin(index, stackType, &G_Mixer.mutex_plugins, ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_swapPlugins(Channel *ch, int index1, int index2, int stackType) +{ + G_PluginHost.swapPlugin(index1, index2, stackType, &G_Mixer.mutex_plugins, + ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_freePlugin(Channel *ch, int index, int stackType) +{ + G_PluginHost.freePlugin(index, stackType, &G_Mixer.mutex_plugins, ch); +} + + +#endif diff --git a/src/glue/plugin.h b/src/glue/plugin.h new file mode 100644 index 0000000..02e8278 --- /dev/null +++ b/src/glue/plugin.h @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef __GLUE_PLUGIN_H__ +#define __GLUE_PLUGIN_H__ + + +#ifdef WITH_VST + +class Plugin *glue_addPlugin(class Channel *ch, int index, int stackType); + +void glue_swapPlugins(class Channel *ch, int indexP1, int indexP2, int stackType); + +void glue_freePlugin(class Channel *ch, int index, int stackType); + +#endif + + +#endif diff --git a/src/glue/storage.cpp b/src/glue/storage.cpp index 41924d9..997389a 100644 --- a/src/glue/storage.cpp +++ b/src/glue/storage.cpp @@ -28,11 +28,6 @@ * -------------------------------------------------------------------------- */ -#include "../gui/elems/ge_column.h" -#include "../gui/elems/ge_keyboard.h" -#include "../gui/dialogs/gd_mainWindow.h" -#include "../gui/dialogs/gd_warnings.h" -#include "../gui/dialogs/gd_browser.h" #include "../core/mixer.h" #include "../core/mixerHandler.h" #include "../core/channel.h" @@ -46,6 +41,11 @@ #include "../core/wave.h" #include "../utils/gui.h" #include "../utils/log.h" +#include "../gui/elems/mainWindow/keyboard/column.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" +#include "../gui/dialogs/gd_mainWindow.h" +#include "../gui/dialogs/gd_warnings.h" +#include "../gui/dialogs/gd_browser.h" #include "main.h" // TODO - remove, used only for DEPR calls #include "channel.h" #include "storage.h" @@ -91,7 +91,7 @@ static void __glue_fillPatchGlobalsPlugins__(vector *host, vectorkeyboard->getTotalColumns(); i++) { - gColumn *gCol = G_MainWin->keyboard->getColumn(i); + geColumn *gCol = G_MainWin->keyboard->getColumn(i); Patch::column_t pCol; pCol.index = gCol->getIndex(); pCol.width = gCol->w(); diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp index 5c42d26..e47076d 100644 --- a/src/gui/dialogs/gd_about.cpp +++ b/src/gui/dialogs/gd_about.cpp @@ -33,7 +33,9 @@ #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../core/graphics.h" -#include "../../deps/juce/config.h" +#ifdef WITH_VST + #include "../../deps/juce-config.h" +#endif #include "../../utils/gui.h" #include "../elems/ge_mixed.h" #include "gd_about.h" diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp index 9d70506..cf860be 100644 --- a/src/gui/dialogs/gd_actionEditor.cpp +++ b/src/gui/dialogs/gd_actionEditor.cpp @@ -40,6 +40,7 @@ #include "../elems/muteEditor.h" #include "../elems/noteEditor.h" #include "../elems/ge_mixed.h" +#include "../elems/basics/scroll.h" #include "gd_actionEditor.h" @@ -94,7 +95,7 @@ gdActionEditor::gdActionEditor(Channel *chan) /* main scroller: contains all widgets */ - scroller = new gScroll(8, 36, w()-16, h()-44); + scroller = new geScroll(8, 36, w()-16, h()-44); if (chan->type == CHANNEL_SAMPLE) { diff --git a/src/gui/dialogs/gd_actionEditor.h b/src/gui/dialogs/gd_actionEditor.h index 435619d..c7f60f2 100644 --- a/src/gui/dialogs/gd_actionEditor.h +++ b/src/gui/dialogs/gd_actionEditor.h @@ -72,7 +72,7 @@ public: class gGridTool *gridTool; class gClick *zoomIn; class gClick *zoomOut; - class gScroll *scroller; // widget container + class geScroll *scroller; // widget container class geActionEditor *ac; class geMuteEditor *mc; diff --git a/src/gui/dialogs/gd_beatsInput.cpp b/src/gui/dialogs/gd_beatsInput.cpp index e77e839..35ca62e 100644 --- a/src/gui/dialogs/gd_beatsInput.cpp +++ b/src/gui/dialogs/gd_beatsInput.cpp @@ -32,6 +32,7 @@ #include "../../core/conf.h" #include "../../core/const.h" #include "../../glue/main.h" +#include "../elems/ge_mixed.h" #include "gd_beatsInput.h" #include "gd_mainWindow.h" diff --git a/src/gui/dialogs/gd_browser.cpp b/src/gui/dialogs/gd_browser.cpp index 0c45a18..cbb7e46 100644 --- a/src/gui/dialogs/gd_browser.cpp +++ b/src/gui/dialogs/gd_browser.cpp @@ -28,17 +28,11 @@ #include "../../core/graphics.h" -#include "../../core/wave.h" -#include "../../core/channel.h" -#include "../../core/sampleChannel.h" #include "../../core/conf.h" #include "../../core/const.h" -#include "../../glue/main.h" -#include "../../glue/channel.h" -#include "../../glue/storage.h" #include "../../utils/gui.h" -#include "../elems/ge_browser.h" -#include "../elems/channel.h" +#include "../elems/ge_mixed.h" +#include "../elems/browser.h" #include "gd_browser.h" @@ -54,19 +48,22 @@ gdBaseBrowser::gdBaseBrowser(int x, int y, int w, int h, const string &title, { set_non_modal(); - groupTop = new Fl_Group(8, 8, w-16, 20); - where = new gInput(groupTop->x(), groupTop->y(), 152, 20); - updir = new gClick(groupTop->x()+groupTop->w()-20, groupTop->y(), 20, 20, "", updirOff_xpm, updirOn_xpm); + groupTop = new Fl_Group(8, 8, w-16, 40); + hiddenFiles = new gCheck(groupTop->x(), groupTop->y(), 400, 20, "Show hidden files"); + where = new gInput(groupTop->x(), hiddenFiles->y()+hiddenFiles->h(), 152, 20); + updir = new gClick(groupTop->x()+groupTop->w()-20, where->y(), 20, 20, "", updirOff_xpm, updirOn_xpm); groupTop->end(); groupTop->resizable(where); + hiddenFiles->callback(cb_toggleHiddenFiles, (void*) this); + where->readonly(true); where->cursor_color(COLOR_BG_DARK); where->value(path.c_str()); updir->callback(cb_up, (void*) this); - browser = new gBrowser(8, groupTop->y()+groupTop->h()+8, w-16, h-73); + browser = new geBrowser(8, groupTop->y()+groupTop->h()+8, w-16, h-93); browser->loadDir(path); if (path == G_Conf.browserLastPath) browser->preselect(G_Conf.browserPosition, G_Conf.browserLastValue); @@ -113,12 +110,14 @@ gdBaseBrowser::~gdBaseBrowser() void gdBaseBrowser::cb_up (Fl_Widget *v, void *p) { ((gdBaseBrowser*)p)->__cb_up(); } void gdBaseBrowser::cb_close(Fl_Widget *v, void *p) { ((gdBaseBrowser*)p)->__cb_close(); } +void gdBaseBrowser::cb_toggleHiddenFiles(Fl_Widget *v, void *p) { ((gdBaseBrowser*)p)->__cb_toggleHiddenFiles(); } /* -------------------------------------------------------------------------- */ -void gdBaseBrowser::__cb_up() { +void gdBaseBrowser::__cb_up() +{ string dir = browser->getCurrentDir(); dir = dir.substr(0, dir.find_last_of(G_SLASH_STR)); // remove up to the next slash browser->loadDir(dir); @@ -129,7 +128,8 @@ void gdBaseBrowser::__cb_up() { /* -------------------------------------------------------------------------- */ -void gdBaseBrowser::__cb_close() { +void gdBaseBrowser::__cb_close() +{ do_callback(); } @@ -137,6 +137,15 @@ void gdBaseBrowser::__cb_close() { /* -------------------------------------------------------------------------- */ +void gdBaseBrowser::__cb_toggleHiddenFiles() +{ + browser->toggleHiddenFiles(); +} + + +/* -------------------------------------------------------------------------- */ + + void gdBaseBrowser::setStatusBar(float v) { status->value(status->value() + v); @@ -147,6 +156,33 @@ void gdBaseBrowser::setStatusBar(float v) /* -------------------------------------------------------------------------- */ +void gdBaseBrowser::showStatusBar() +{ + status->show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdBaseBrowser::hideStatusBar() +{ + status->hide(); +} + + +/* -------------------------------------------------------------------------- */ + + +string gdBaseBrowser::getCurrentPath() +{ + return where->value(); +} + + +/* -------------------------------------------------------------------------- */ + + string gdBaseBrowser::getSelectedItem() { return browser->getSelectedItem(); @@ -166,7 +202,7 @@ gdSaveBrowser::gdSaveBrowser(int x, int y, int w, int h, const string &title, where->size(groupTop->w()-236, 20); - name = new gInput(where->x()+where->w()+8, 8, 200, 20); + name = new gInput(where->x()+where->w()+8, where->y(), 200, 20); name->value(_name.c_str()); groupTop->add(name); @@ -210,6 +246,15 @@ void gdSaveBrowser::__cb_down() /* -------------------------------------------------------------------------- */ +string gdSaveBrowser::getName() +{ + return name->value(); +} + + +/* -------------------------------------------------------------------------- */ + + void gdSaveBrowser::__cb_save() { callback((void*) this); diff --git a/src/gui/dialogs/gd_browser.h b/src/gui/dialogs/gd_browser.h index bf797ec..5606b52 100644 --- a/src/gui/dialogs/gd_browser.h +++ b/src/gui/dialogs/gd_browser.h @@ -31,9 +31,6 @@ #define GD_BROWSER_H -#include -#include -#include "../elems/ge_mixed.h" #include "../elems/ge_window.h" @@ -42,18 +39,21 @@ class gdBaseBrowser : public gWindow protected: class Fl_Group *groupTop; - class gBrowser *browser; + class gCheck *hiddenFiles; + class geBrowser *browser; class gClick *ok; class gClick *cancel; class gInput *where; class gClick *updir; class gProgress *status; - static void cb_up (Fl_Widget *v, void *p); - static void cb_close(Fl_Widget *w, void *p); + static void cb_up (Fl_Widget *v, void *p); + static void cb_close (Fl_Widget *w, void *p); + static void cb_toggleHiddenFiles(Fl_Widget *w, void *p); - inline void __cb_up (); - inline void __cb_close(); + inline void __cb_up (); + inline void __cb_close (); + inline void __cb_toggleHiddenFiles(); /* Callback * Fired when the save/load button is pressed. */ @@ -79,12 +79,13 @@ public: void setStatusBar(float v); - inline gProgress *getStatusBar() { return status; } // TODO - remove with Patch_DEPR_ - inline void showStatusBar() { status->show(); } - inline void hideStatusBar() { status->hide(); } - inline Channel *getChannel() { return channel; } - inline void fireCallback() { callback((void*) this); } - inline string getCurrentPath() { return where->value(); } + gProgress *getStatusBar() { return status; } // TODO - remove with Patch_DEPR_ + void showStatusBar(); + void hideStatusBar(); + string getCurrentPath(); + + Channel *getChannel() { return channel; } + void fireCallback() { callback((void*) this); } }; @@ -109,7 +110,7 @@ public: const string &path, const string &name, void (*callback)(void*), class Channel *ch); - string getName() { return name->value(); } + string getName(); }; diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp index 832b75a..10c49ad 100644 --- a/src/gui/dialogs/gd_config.cpp +++ b/src/gui/dialogs/gd_config.cpp @@ -39,6 +39,7 @@ #include "../../utils/log.h" #include "../../utils/string.h" #include "../elems/ge_mixed.h" +#include "../elems/basics/boxtypes.h" #include "gd_config.h" #include "gd_keyGrabber.h" #include "gd_devInfo.h" @@ -954,6 +955,10 @@ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration") resize(G_Conf.configX, G_Conf.configY, this->w(), this->h()); Fl_Tabs *tabs = new Fl_Tabs(8, 8, w-16, h-44); + tabs->box(G_CUSTOM_BORDER_BOX); + tabs->labelcolor(COLOR_TEXT_0); + tabs->begin(); + tabAudio = new gTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabMidi = new gTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabBehaviors = new gTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); @@ -969,10 +974,6 @@ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration") end(); - tabs->box(FL_FLAT_BOX); // TODO - G_BOX crashes FLTK 1.3.3 - - tabs->labelcolor(COLOR_TEXT_0); - save->callback(cb_save_config, (void*)this); cancel->callback(cb_cancel, (void*)this); diff --git a/src/gui/dialogs/gd_editor.cpp b/src/gui/dialogs/gd_editor.cpp index af5d55b..881b4ab 100644 --- a/src/gui/dialogs/gd_editor.cpp +++ b/src/gui/dialogs/gd_editor.cpp @@ -35,10 +35,10 @@ #include "../../core/sampleChannel.h" #include "../../core/mixer.h" #include "../../core/wave.h" -#include "../elems/channel.h" #include "../elems/ge_waveform.h" #include "../elems/ge_mixed.h" #include "../elems/ge_waveTools.h" +#include "../elems/mainWindow/keyboard/channel.h" #include "gd_warnings.h" #include "gd_editor.h" @@ -407,7 +407,7 @@ void gdEditor::__cb_reload() ch->load(ch->wave->pathfile.c_str(), G_Conf.samplerate, G_Conf.rsmpQuality); glue_setBoost(this, ch, DEFAULT_BOOST, true); - glue_setPitch(this, ch, gDEFAULT_PITCH, true); + glue_setPitch(this, ch, G_DEFAULT_PITCH, true); glue_setPanning(this, ch, 1.0f); pan->value(1.0f); // glue_setPanning doesn't do it pan->redraw(); // glue_setPanning doesn't do it diff --git a/src/gui/dialogs/gd_keyGrabber.cpp b/src/gui/dialogs/gd_keyGrabber.cpp index 508867b..d76e41f 100644 --- a/src/gui/dialogs/gd_keyGrabber.cpp +++ b/src/gui/dialogs/gd_keyGrabber.cpp @@ -33,10 +33,10 @@ #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../utils/log.h" -#include "../elems/ge_keyboard.h" #include "../elems/ge_mixed.h" -#include "../elems/channel.h" -#include "../elems/channelButton.h" +#include "../elems/mainWindow/keyboard/keyboard.h" +#include "../elems/mainWindow/keyboard/channel.h" +#include "../elems/mainWindow/keyboard/channelButton.h" #include "gd_keyGrabber.h" #include "gd_config.h" #include "gd_mainWindow.h" diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp index dba5764..0220f7a 100644 --- a/src/gui/dialogs/gd_mainWindow.cpp +++ b/src/gui/dialogs/gd_mainWindow.cpp @@ -27,43 +27,23 @@ * -------------------------------------------------------------------------- */ -#ifdef __linux__ - #include // for mkdir -#endif - - -#include "../../core/graphics.h" -#include "../../core/mixer.h" -#include "../../core/recorder.h" -#include "../../core/mixerHandler.h" -#include "../../core/channel.h" -#include "../../core/sampleChannel.h" +#include +#include "../../core/const.h" #include "../../core/init.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/patch.h" -#include "../../core/conf.h" -#include "../../core/pluginHost.h" -#include "../../glue/main.h" -#include "../../glue/storage.h" -#include "../elems/ge_keyboard.h" +#include "../../utils/gui.h" +#include "../elems/ge_mixed.h" +#include "../elems/basics/boxtypes.h" +#include "../elems/mainWindow/mainIO.h" +#include "../elems/mainWindow/mainMenu.h" +#include "../elems/mainWindow/mainTimer.h" +#include "../elems/mainWindow/mainTransport.h" +#include "../elems/mainWindow/beatMeter.h" +#include "../elems/mainWindow/keyboard/keyboard.h" #include "gd_warnings.h" -#include "gd_bpmInput.h" -#include "gd_beatsInput.h" -#include "gd_midiInput.h" -#include "gd_about.h" -#include "gd_config.h" -#include "gd_browser.h" #include "gd_mainWindow.h" -#include "gd_pluginList.h" -extern Mixer G_Mixer; -extern Patch_DEPR_ G_Patch_DEPR_; -extern Patch G_Patch; -extern Conf G_Conf; extern gdMainWindow *G_MainWin; -extern bool G_quit; -extern bool G_audio_status; gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **argv) @@ -72,30 +52,37 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg Fl::visible_focus(0); Fl::background(25, 25, 25); - Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2); // custom box G_BOX + + Fl::set_boxtype(G_CUSTOM_BORDER_BOX, g_customBorderBox, 1, 1, 2, 2); + Fl::set_boxtype(G_CUSTOM_UP_BOX, g_customUpBox, 1, 1, 2, 2); + Fl::set_boxtype(G_CUSTOM_DOWN_BOX, g_customDownBox, 1, 1, 2, 2); + + Fl::set_boxtype(FL_BORDER_BOX, G_CUSTOM_BORDER_BOX); + Fl::set_boxtype(FL_UP_BOX, G_CUSTOM_UP_BOX); + Fl::set_boxtype(FL_DOWN_BOX, G_CUSTOM_DOWN_BOX); size_range(GUI_WIDTH, GUI_HEIGHT); - menu = new gMenu(8, -1); - inOut = new gInOut(412, 8); - controller = new gController(8, 39); - timing = new gTiming(628, 44); - beatMeter = new gBeatMeter(100, 83, 609, 20); - keyboard = new gKeyboard(8, 122, w()-16, 380); + mainMenu = new geMainMenu(8, -1); + mainIO = new geMainIO(412, 8); + mainTransport = new geMainTransport(8, 39); + mainTimer = new geMainTimer(628, 44); + beatMeter = new geBeatMeter(100, 83, 609, 20); + keyboard = new geKeyboard(8, 122, w()-16, 380); /* zone 1 - menus, and I/O tools */ Fl_Group *zone1 = new Fl_Group(8, 8, W-16, 20); - zone1->add(menu); + zone1->add(mainMenu); zone1->resizable(new Fl_Box(300, 8, 80, 20)); - zone1->add(inOut); + zone1->add(mainIO); - /* zone 2 - controller and timing tools */ + /* zone 2 - mainTransport and timing tools */ - Fl_Group *zone2 = new Fl_Group(8, controller->y(), W-16, controller->h()); - zone2->add(controller); - zone2->resizable(new Fl_Box(controller->x()+controller->w()+4, zone2->y(), 80, 20)); - zone2->add(timing); + Fl_Group *zone2 = new Fl_Group(8, mainTransport->y(), W-16, mainTransport->h()); + zone2->add(mainTransport); + zone2->resizable(new Fl_Box(mainTransport->x()+mainTransport->w()+4, zone2->y(), 80, 20)); + zone2->add(mainTimer); /* zone 3 - beat meter */ @@ -135,414 +122,3 @@ void gdMainWindow::__cb_endprogram() hide(); delete this; } - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gInOut::gInOut(int x, int y) - : Fl_Group(x, y, 396, 20) -{ - begin(); - -#if defined(WITH_VST) - masterFxIn = new gFxButton (x, y, 20, 20, fxOff_xpm, fxOn_xpm); - inVol = new gDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20); - inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+4, 140, 12); - inToOut = new gClick (inMeter->x()+inMeter->w()+4, y+4, 12, 12, "", inputToOutputOff_xpm, inputToOutputOn_xpm); - outMeter = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+4, 140, 12); - outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); - masterFxOut = new gFxButton (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm); -#else - inVol = new gDial (x+62, y, 20, 20); - inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 12); - outMeter = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 12); - outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); -#endif - - end(); - - resizable(NULL); // don't resize any widget - - outVol->callback(cb_outVol, (void*)this); - outVol->value(G_Mixer.outVol); - inVol->callback(cb_inVol, (void*)this); - inVol->value(G_Mixer.inVol); - -#ifdef WITH_VST - masterFxOut->callback(cb_masterFxOut, (void*)this); - masterFxIn->callback(cb_masterFxIn, (void*)this); - inToOut->callback(cb_inToOut, (void*)this); - inToOut->type(FL_TOGGLE_BUTTON); -#endif -} - - -/* -------------------------------------------------------------------------- */ - - -void gInOut::cb_outVol (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_outVol(); } -void gInOut::cb_inVol (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_inVol(); } -#ifdef WITH_VST -void gInOut::cb_masterFxOut(Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_masterFxOut(); } -void gInOut::cb_masterFxIn (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_masterFxIn(); } -void gInOut::cb_inToOut (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_inToOut(); } -#endif - - -/* -------------------------------------------------------------------------- */ - - -void gInOut::__cb_outVol() -{ - glue_setOutVol(outVol->value()); -} - - -/* -------------------------------------------------------------------------- */ - - -void gInOut::__cb_inVol() -{ - glue_setInVol(inVol->value()); -} - - -/* -------------------------------------------------------------------------- */ - - -#ifdef WITH_VST -void gInOut::__cb_masterFxOut() -{ - gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST); -} - -void gInOut::__cb_masterFxIn() -{ - gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST); -} - -void gInOut::__cb_inToOut() -{ - G_Mixer.inToOut = inToOut->value(); -} -#endif - - -/* -------------------------------------------------------------------------- */ - - -void gInOut::refresh() -{ - outMeter->mixerPeak = G_Mixer.peakOut; - inMeter->mixerPeak = G_Mixer.peakIn; - outMeter->redraw(); - inMeter->redraw(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gMenu::gMenu(int x, int y) - : Fl_Group(x, y, 300, 20) -{ - begin(); - - file = new gClick(x, y, 70, 21, "file"); - edit = new gClick(file->x()+file->w()+4, y, 70, 21, "edit"); - config = new gClick(edit->x()+edit->w()+4, y, 70, 21, "config"); - about = new gClick(config->x()+config->w()+4, y, 70, 21, "about"); - - end(); - - resizable(NULL); // don't resize any widget - - about->callback(cb_about, (void*)this); - file->callback(cb_file, (void*)this); - edit->callback(cb_edit, (void*)this); - config->callback(cb_config, (void*)this); -} - - -/* -------------------------------------------------------------------------- */ - - -void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); } -void gMenu::cb_config(Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_config(); } -void gMenu::cb_file (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); } -void gMenu::cb_edit (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); } - - -/* -------------------------------------------------------------------------- */ - - -void gMenu::__cb_about() -{ - gu_openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT); -} - - -/* -------------------------------------------------------------------------- */ - - -void gMenu::__cb_config() -{ - gu_openSubWindow(G_MainWin, new gdConfig(380, 370), WID_CONFIG); -} - - -/* -------------------------------------------------------------------------- */ - - -void gMenu::__cb_file() -{ - /* An Fl_Menu_Button is made of many Fl_Menu_Item */ - - Fl_Menu_Item menu[] = { - {"Open patch or project..."}, - {"Save patch..."}, - {"Save project..."}, - {"Quit Giada"}, - {0} - }; - - Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); - b->textsize(GUI_FONT_SIZE_BASE); - b->textcolor(COLOR_TEXT_0); - b->color(COLOR_BG_0); - - const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); - if (!m) return; - - - if (strcmp(m->label(), "Open patch or project...") == 0) { - //gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH); - //gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); - gWindow *childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, - G_Conf.browserW, G_Conf.browserH, "Load patch or project", - G_Conf.patchPath, glue_loadPatch, NULL); - gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); - return; - } - if (strcmp(m->label(), "Save patch...") == 0) { - if (G_Mixer.hasLogicalSamples() || G_Mixer.hasEditedSamples()) - if (!gdConfirmWin("Warning", "You should save a project in order to store\nyour takes and/or processed samples.")) - return; - gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, - G_Conf.browserW, G_Conf.browserH, "Save patch", - G_Conf.patchPath, G_Patch.name, glue_savePatch, NULL); - gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); - return; - } - if (strcmp(m->label(), "Save project...") == 0) { - gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, - G_Conf.browserW, G_Conf.browserH, "Save project", - G_Conf.patchPath, G_Patch.name, glue_saveProject, NULL); - gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); - return; - } - if (strcmp(m->label(), "Quit Giada") == 0) { - G_MainWin->do_callback(); - return; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void gMenu::__cb_edit() -{ - Fl_Menu_Item menu[] = { - {"Clear all samples"}, - {"Clear all actions"}, - {"Remove empty columns"}, - {"Reset to init state"}, - {"Setup global MIDI input..."}, - {0} - }; - - /* clear all actions disabled if no recs, clear all samples disabled - * if no samples. */ - - menu[1].deactivate(); - - for (unsigned i=0; ihasActions) { - menu[1].activate(); - break; - } - for (unsigned i=0; itype == CHANNEL_SAMPLE) - if (((SampleChannel*)G_Mixer.channels.at(i))->wave != NULL) { - menu[0].activate(); - break; - } - - Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); - b->textsize(GUI_FONT_SIZE_BASE); - b->textcolor(COLOR_TEXT_0); - b->color(COLOR_BG_0); - - const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); - if (!m) return; - - if (strcmp(m->label(), "Clear all samples") == 0) { - if (!gdConfirmWin("Warning", "Clear all samples: are you sure?")) - return; - G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); - glue_clearAllSamples(); - return; - } - if (strcmp(m->label(), "Clear all actions") == 0) { - if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) - return; - G_MainWin->delSubWindow(WID_ACTION_EDITOR); - glue_clearAllRecs(); - return; - } - if (strcmp(m->label(), "Reset to init state") == 0) { - if (!gdConfirmWin("Warning", "Reset to init state: are you sure?")) - return; - gu_closeAllSubwindows(); - glue_resetToInitState(); - return; - } - if (strcmp(m->label(), "Remove empty columns") == 0) { - G_MainWin->keyboard->organizeColumns(); - return; - } - if (strcmp(m->label(), "Setup global MIDI input...") == 0) { - gu_openSubWindow(G_MainWin, new gdMidiInputMaster(), 0); - return; - } -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gTiming::gTiming(int x, int y) - : Fl_Group(x, y, 180, 20) -{ - begin(); - - quantizer = new gChoice(x, y, 40, 20, "", false); - bpm = new gClick (quantizer->x()+quantizer->w()+4, y, 40, 20); - meter = new gClick (bpm->x()+bpm->w()+8, y, 40, 20, "4/1"); - multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm); - divider = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm); - - end(); - - resizable(NULL); // don't resize any widget - - char buf[6]; snprintf(buf, 6, "%f", G_Mixer.bpm); - bpm->copy_label(buf); - - bpm->callback(cb_bpm, (void*)this); - meter->callback(cb_meter, (void*)this); - multiplier->callback(cb_multiplier, (void*)this); - divider->callback(cb_divider, (void*)this); - - quantizer->add("off", 0, cb_quantizer, (void*)this); - quantizer->add("1b", 0, cb_quantizer, (void*)this); - quantizer->add("2b", 0, cb_quantizer, (void*)this); - quantizer->add("3b", 0, cb_quantizer, (void*)this); - quantizer->add("4b", 0, cb_quantizer, (void*)this); - quantizer->add("6b", 0, cb_quantizer, (void*)this); - quantizer->add("8b", 0, cb_quantizer, (void*)this); - quantizer->value(0); // "off" by default -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::cb_bpm (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); } -void gTiming::cb_meter (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_meter(); } -void gTiming::cb_quantizer (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_quantizer(); } -void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multiplier(); } -void gTiming::cb_divider (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); } - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::__cb_bpm() -{ - gu_openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::__cb_meter() -{ - gu_openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::__cb_quantizer() -{ - glue_quantize(quantizer->value()); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::__cb_multiplier() -{ - glue_beatsMultiply(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::__cb_divider() -{ - glue_beatsDivide(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::setBpm(const char *v) -{ - bpm->copy_label(v); -} - - -void gTiming::setBpm(float v) -{ - char buf[6]; - sprintf(buf, "%.01f", v); // only 1 decimal place (e.g. 120.0) - bpm->copy_label(buf); -} - - -/* -------------------------------------------------------------------------- */ - - -void gTiming::setMeter(int beats, int bars) -{ - char buf[8]; - sprintf(buf, "%d/%d", beats, bars); - meter->copy_label(buf); -} diff --git a/src/gui/dialogs/gd_mainWindow.h b/src/gui/dialogs/gd_mainWindow.h index a0a0489..6b07917 100644 --- a/src/gui/dialogs/gd_mainWindow.h +++ b/src/gui/dialogs/gd_mainWindow.h @@ -30,145 +30,27 @@ #define GD_MAINWINDOW_H -#include -#include -#include "../elems/ge_mixed.h" #include "../elems/ge_window.h" -#include "../elems/ge_controller.h" - - -/* -------------------------------------------------------------------------- */ class gdMainWindow : public gWindow { private: - static void cb_endprogram (Fl_Widget *v, void *p); + static void cb_endprogram (class Fl_Widget *v, void *p); inline void __cb_endprogram(); public: - class gKeyboard *keyboard; - class gBeatMeter *beatMeter; - class gMenu *menu; - class gInOut *inOut; - class gController *controller; - class gTiming *timing; + class geKeyboard *keyboard; + class geBeatMeter *beatMeter; + class geMainMenu *mainMenu; + class geMainIO *mainIO; + class geMainTimer *mainTimer; + class geMainTransport *mainTransport; gdMainWindow(int w, int h, const char *title, int argc, char **argv); }; -/* -------------------------------------------------------------------------- */ - - -class gInOut : public Fl_Group -{ -private: - - class gSoundMeter *outMeter; - class gSoundMeter *inMeter; - class gDial *outVol; - class gDial *inVol; -#ifdef WITH_VST - class gFxButton *masterFxOut; - class gFxButton *masterFxIn; - class gClick *inToOut; -#endif - - static void cb_outVol (Fl_Widget *v, void *p); - static void cb_inVol (Fl_Widget *v, void *p); -#ifdef WITH_VST - static void cb_masterFxOut(Fl_Widget *v, void *p); - static void cb_masterFxIn (Fl_Widget *v, void *p); - static void cb_inToOut (Fl_Widget *v, void *p); -#endif - - inline void __cb_outVol (); - inline void __cb_inVol (); -#ifdef WITH_VST - inline void __cb_masterFxOut(); - inline void __cb_masterFxIn (); - inline void __cb_inToOut (); -#endif - -public: - - gInOut(int x, int y); - - void refresh(); - - inline void setOutVol(float v) { outVol->value(v); } - inline void setInVol (float v) { inVol->value(v); } -#ifdef WITH_VST - inline void setMasterFxOutFull(bool v) { masterFxOut->full = v; masterFxOut->redraw(); } - inline void setMasterFxInFull(bool v) { masterFxIn->full = v; masterFxIn->redraw(); } -#endif -}; - - -/* -------------------------------------------------------------------------- */ - - -class gMenu : public Fl_Group -{ -private: - - class gClick *file; - class gClick *edit; - class gClick *config; - class gClick *about; - - static void cb_about (Fl_Widget *v, void *p); - static void cb_config(Fl_Widget *v, void *p); - static void cb_file (Fl_Widget *v, void *p); - static void cb_edit (Fl_Widget *v, void *p); - - inline void __cb_about (); - inline void __cb_config(); - inline void __cb_file (); - inline void __cb_edit (); - -public: - - gMenu(int x, int y); -}; - - -/* -------------------------------------------------------------------------- */ - - -class gTiming : public Fl_Group -{ -private: - - class gClick *bpm; - class gClick *meter; - class gChoice *quantizer; - class gClick *multiplier; - class gClick *divider; - - static void cb_bpm (Fl_Widget *v, void *p); - static void cb_meter (Fl_Widget *v, void *p); - static void cb_quantizer (Fl_Widget *v, void *p); - static void cb_multiplier(Fl_Widget *v, void *p); - static void cb_divider (Fl_Widget *v, void *p); - - inline void __cb_bpm(); - inline void __cb_meter(); - inline void __cb_quantizer(); - inline void __cb_multiplier(); - inline void __cb_divider(); - -public: - - gTiming(int x, int y); - - void setBpm(const char *v); - void setBpm(float v); - void setMeter(int beats, int bars); -}; - - #endif diff --git a/src/gui/dialogs/gd_midiInput.cpp b/src/gui/dialogs/gd_midiInput.cpp deleted file mode 100644 index e713416..0000000 --- a/src/gui/dialogs/gd_midiInput.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiInput - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../utils/gui.h" -#include "../../core/kernelMidi.h" -#include "../../core/conf.h" -#include "../../core/const.h" -#include "../../core/sampleChannel.h" -#include "../../utils/log.h" -#include "../../utils/string.h" -#include "../elems/ge_mixed.h" -#include "../elems/ge_midiIoTools.h" -#include "gd_midiInput.h" - - -extern Conf G_Conf; -extern KernelMidi G_KernelMidi; - - -using std::string; - - -gdMidiInput::gdMidiInput(int w, int h, const char *title) - : gWindow(w, h, title) -{ -} - - -/* -------------------------------------------------------------------------- */ - - -gdMidiInput::~gdMidiInput() -{ - G_KernelMidi.stopMidiLearn(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInput::stopMidiLearn(gLearner *learner) -{ - G_KernelMidi.stopMidiLearn(); - learner->updateValue(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) -{ - *param = msg; - stopMidiLearn(l); - gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInput::cb_learn(uint32_t msg, void *d) -{ - cbData *data = (cbData*) d; - gdMidiInput *window = (gdMidiInput*) data->window; - gLearner *learner = data->learner; - uint32_t *param = learner->param; - window->__cb_learn(param, msg, learner); - free(data); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInput::cb_close(Fl_Widget *w, void *p) { ((gdMidiInput*)p)->__cb_close(); } - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInput::__cb_close() -{ - do_callback(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gdMidiInputChannel::gdMidiInputChannel(Channel *ch) - : gdMidiInput(300, 230, "MIDI Input Setup"), - ch(ch) -{ - string title = "MIDI Input Setup (channel " + gu_itoa(ch->index+1) + ")"; - label(title.c_str()); - - set_modal(); - - enable = new gCheck(8, 8, 120, 20, "enable MIDI input"); - new gLearner(8, 30, w()-16, "key press", cb_learn, &ch->midiInKeyPress); - new gLearner(8, 54, w()-16, "key release", cb_learn, &ch->midiInKeyRel); - new gLearner(8, 78, w()-16, "key kill", cb_learn, &ch->midiInKill); - new gLearner(8, 102, w()-16, "arm", cb_learn, &ch->midiInArm); - new gLearner(8, 126, w()-16, "mute", cb_learn, &ch->midiInMute); - new gLearner(8, 150, w()-16, "solo", cb_learn, &ch->midiInSolo); - new gLearner(8, 174, w()-16, "volume", cb_learn, &ch->midiInVolume); - int yy = 202; - - if (ch->type == CHANNEL_SAMPLE) { - size(300, 278); - new gLearner(8, 198, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); - new gLearner(8, 222, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); - yy = 250; - } - - ok = new gButton(w()-88, yy, 80, 20, "Close"); - ok->callback(cb_close, (void*)this); - - enable->value(ch->midiIn); - enable->callback(cb_enable, (void*)this); - - gu_setFavicon(this); - show(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiInputChannel*)p)->__cb_enable(); } - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiInputChannel::__cb_enable() -{ - ch->midiIn = enable->value(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gdMidiInputMaster::gdMidiInputMaster() - : gdMidiInput(300, 256, "MIDI Input Setup (global)") -{ - set_modal(); - - new gLearner(8, 8, w()-16, "rewind", &cb_learn, &G_Conf.midiInRewind); - new gLearner(8, 32, w()-16, "play/stop", &cb_learn, &G_Conf.midiInStartStop); - new gLearner(8, 56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec); - new gLearner(8, 80, w()-16, "input recording", &cb_learn, &G_Conf.midiInInputRec); - new gLearner(8, 104, w()-16, "metronome", &cb_learn, &G_Conf.midiInMetronome); - new gLearner(8, 128, w()-16, "input volume", &cb_learn, &G_Conf.midiInVolumeIn); - new gLearner(8, 152, w()-16, "output volume", &cb_learn, &G_Conf.midiInVolumeOut); - new gLearner(8, 176, w()-16, "sequencer ×2", &cb_learn, &G_Conf.midiInBeatDouble); - new gLearner(8, 200, w()-16, "sequencer ÷2", &cb_learn, &G_Conf.midiInBeatHalf); - ok = new gButton(w()-88, 228, 80, 20, "Close"); - - ok->callback(cb_close, (void*)this); - - gu_setFavicon(this); - show(); -} diff --git a/src/gui/dialogs/gd_midiInput.h b/src/gui/dialogs/gd_midiInput.h deleted file mode 100644 index eb236e7..0000000 --- a/src/gui/dialogs/gd_midiInput.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiInput - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GD_MIDI_INPUT_H -#define GD_MIDI_INPUT_H - - -#include "../elems/ge_window.h" - - -class gdMidiInput : public gWindow -{ -protected: - - class gClick *ok; - - void stopMidiLearn(class gLearner *l); - - /* cb_learn - * callback attached to kernelMidi to learn various actions. */ - - static void cb_learn (uint32_t msg, void *data); - inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l); - - static void cb_close (Fl_Widget *w, void *p); - inline void __cb_close(); - -public: - - gdMidiInput(int w, int h, const char *title); - ~gdMidiInput(); -}; - - -/* -------------------------------------------------------------------------- */ - - -class gdMidiInputChannel : public gdMidiInput -{ -private: - - class Channel *ch; - - class gCheck *enable; - - //gVector items; for future use, with vst parameters - - static void cb_enable (Fl_Widget *w, void *p); - inline void __cb_enable(); - -public: - - gdMidiInputChannel(class Channel *ch); -}; - - -/* -------------------------------------------------------------------------- */ - - -class gdMidiInputMaster : public gdMidiInput -{ -public: - - gdMidiInputMaster(); -}; - - -#endif diff --git a/src/gui/dialogs/gd_midiOutput.cpp b/src/gui/dialogs/gd_midiOutput.cpp deleted file mode 100644 index 5b2be1f..0000000 --- a/src/gui/dialogs/gd_midiOutput.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiOutput - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/channel.h" -#include "../../core/sampleChannel.h" -#include "../../core/conf.h" -#include "../../core/midiChannel.h" -#include "../../utils/gui.h" -#include "../../utils/log.h" -#include "../elems/ge_mixed.h" -#include "../elems/channel.h" -#include "../elems/ge_midiIoTools.h" -#include "../elems/ge_keyboard.h" -#include "gd_midiOutput.h" - - -extern Conf G_Conf; -extern KernelMidi G_KernelMidi; - - -gdMidiOutput::gdMidiOutput(int w, int h) - : gWindow(w, h, "Midi Output Setup") -{ -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::stopMidiLearn(gLearner *learner) -{ - G_KernelMidi.stopMidiLearn(); - learner->updateValue(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) -{ - *param = msg; - stopMidiLearn(l); - gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::cb_learn(uint32_t msg, void *d) -{ - cbData *data = (cbData*) d; - gdMidiOutput *window = (gdMidiOutput*) data->window; - gLearner *learner = data->learner; - uint32_t *param = learner->param; - window->__cb_learn(param, msg, learner); - free(data); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutput*)p)->__cb_close(); } - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::__cb_close() -{ - do_callback(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p) -{ - ((gdMidiOutput*)p)->__cb_enableLightning(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::__cb_enableLightning() {} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutput::setTitle(int chanNum) -{ - char title[64]; - sprintf(title, "MIDI Output Setup (channel %d)", chanNum); - copy_label(title); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch) - : gdMidiOutput(300, 168), ch(ch) -{ - setTitle(ch->index+1); - begin(); - - enableOut = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output"); - chanListOut = new gChoice(w()-108, y()+8, 100, 20); - - enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output"); - new gLearner(x()+8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); - new gLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); - new gLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); - - close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); - - end(); - - chanListOut->add("Channel 1"); - chanListOut->add("Channel 2"); - chanListOut->add("Channel 3"); - chanListOut->add("Channel 4"); - chanListOut->add("Channel 5"); - chanListOut->add("Channel 6"); - chanListOut->add("Channel 7"); - chanListOut->add("Channel 8"); - chanListOut->add("Channel 9"); - chanListOut->add("Channel 10"); - chanListOut->add("Channel 11"); - chanListOut->add("Channel 12"); - chanListOut->add("Channel 13"); - chanListOut->add("Channel 14"); - chanListOut->add("Channel 15"); - chanListOut->add("Channel 16"); - chanListOut->value(0); - - if (ch->midiOut) - enableOut->value(1); - else - chanListOut->deactivate(); - - if (ch->midiOutL) - enableLightning->value(1); - - chanListOut->value(ch->midiOutChan); - - enableOut->callback(cb_enableChanList, (void*)this); - close->callback(cb_close, (void*)this); - - set_modal(); - gu_setFavicon(this); - show(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutputMidiCh::cb_close (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); } -void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); } - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutputMidiCh::__cb_enableChanList() -{ - enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutputMidiCh::__cb_close() -{ - ch->midiOut = enableOut->value(); - ch->midiOutChan = chanListOut->value(); - ch->midiOutL = enableLightning->value(); - ch->guiChannel->update(); - do_callback(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch) - : gdMidiOutput(300, 140), ch(ch) -{ - setTitle(ch->index+1); - - enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output"); - new gLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); - new gLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); - new gLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); - - close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); - close->callback(cb_close, (void*)this); - - enableLightning->value(ch->midiOutL); - enableLightning->callback(cb_enableLightning, (void*)this); - - set_modal(); - gu_setFavicon(this); - show(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); } - - -/* -------------------------------------------------------------------------- */ - - -void gdMidiOutputSampleCh::__cb_close() -{ - ch->midiOutL = enableLightning->value(); - do_callback(); -} diff --git a/src/gui/dialogs/gd_midiOutput.h b/src/gui/dialogs/gd_midiOutput.h deleted file mode 100644 index 03cc32a..0000000 --- a/src/gui/dialogs/gd_midiOutput.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ---------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiOutput - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#ifndef GD_MIDI_OUTPUT_H -#define GD_MIDI_OUTPUT_H - - -#include -#include -#include "../elems/ge_window.h" - - -/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI -output master is managed by the configuration window, hence gdMidiOutput deals -only with channels. - -Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set. -In addition MidiOutputMidiCh has the MIDI message output box. */ - -/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another -parent class gdMidiIO to inherit from */ - -class gdMidiOutput : public gWindow -{ -protected: - - class gClick *close; - class gCheck *enableLightning; - - void stopMidiLearn(class gLearner *l); - - /* cb_learn - * callback attached to kernelMidi to learn various actions. */ - - static void cb_learn (uint32_t msg, void *data); - inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l); - - /* cb_close - close current window. */ - - static void cb_close (Fl_Widget *w, void *p); - inline void __cb_close(); - - /* cb_enableLightning - enable MIDI lightning output. */ - - static void cb_enableLightning (Fl_Widget *w, void *p); - inline void __cb_enableLightning(); - - /* setTitle - * set window title. */ - - void setTitle(int chanNum); - -public: - - gdMidiOutput(int w, int h); -}; - - -/* -------------------------------------------------------------------------- */ - - -class gdMidiOutputMidiCh : public gdMidiOutput -{ -private: - - static void cb_enableChanList (Fl_Widget *w, void *p); - inline void __cb_enableChanList(); - - /* __cb_close - override parent method, we need to do more stuff on close. */ - - static void cb_close (Fl_Widget *w, void *p); - inline void __cb_close(); - - class gCheck *enableOut; - class gChoice *chanListOut; - - class MidiChannel *ch; - -public: - - gdMidiOutputMidiCh(class MidiChannel *ch); -}; - - -/* -------------------------------------------------------------------------- */ - - -class gdMidiOutputSampleCh : public gdMidiOutput -{ -private: - - class SampleChannel *ch; - - /* __cb_close - override parent method, we need to do more stuff on close. */ - - static void cb_close (Fl_Widget *w, void *p); - inline void __cb_close(); - -public: - - gdMidiOutputSampleCh(class SampleChannel *ch); -}; - -#endif diff --git a/src/gui/dialogs/gd_pluginChooser.cpp b/src/gui/dialogs/gd_pluginChooser.cpp index d868108..0e20dc1 100644 --- a/src/gui/dialogs/gd_pluginChooser.cpp +++ b/src/gui/dialogs/gd_pluginChooser.cpp @@ -30,9 +30,9 @@ #ifdef WITH_VST +#include "../../glue/plugin.h" #include "../../utils/gui.h" #include "../../core/channel.h" -#include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/pluginHost.h" #include "../elems/ge_pluginBrowser.h" @@ -41,7 +41,6 @@ extern PluginHost G_PluginHost; -extern Mixer G_Mixer; extern Conf G_Conf; @@ -108,7 +107,8 @@ void gdPluginChooser::cb_sort(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->_ /* -------------------------------------------------------------------------- */ -void gdPluginChooser::__cb_close() { +void gdPluginChooser::__cb_close() +{ do_callback(); } @@ -116,7 +116,8 @@ void gdPluginChooser::__cb_close() { /* -------------------------------------------------------------------------- */ -void gdPluginChooser::__cb_sort() { +void gdPluginChooser::__cb_sort() +{ G_PluginHost.sortPlugins(sortMethod->value()); browser->refresh(); } @@ -125,12 +126,13 @@ void gdPluginChooser::__cb_sort() { /* -------------------------------------------------------------------------- */ -void gdPluginChooser::__cb_add() { +void gdPluginChooser::__cb_add() +{ int index = browser->value() - 3; // subtract header lines - if (index >= 0 && index < G_PluginHost.countAvailablePlugins()) { - G_PluginHost.addPlugin(index, stackType, &G_Mixer.mutex_plugins, ch); - do_callback(); - } + if (index < 0) + return; + glue_addPlugin(ch, index, stackType); + do_callback(); } #endif // #ifdef WITH_VST diff --git a/src/gui/dialogs/gd_pluginList.cpp b/src/gui/dialogs/gd_pluginList.cpp index 003ca63..65d8e6d 100644 --- a/src/gui/dialogs/gd_pluginList.cpp +++ b/src/gui/dialogs/gd_pluginList.cpp @@ -39,10 +39,13 @@ #include "../../core/plugin.h" #include "../../core/mixer.h" #include "../../core/channel.h" +#include "../../glue/plugin.h" #include "../../utils/log.h" #include "../../utils/string.h" #include "../elems/ge_mixed.h" -#include "../elems/channel.h" +#include "../elems/basics/boxtypes.h" +#include "../elems/mainWindow/mainIO.h" +#include "../elems/mainWindow/keyboard/channel.h" #include "gd_pluginList.h" #include "gd_pluginChooser.h" #include "gd_pluginWindow.h" @@ -71,7 +74,7 @@ gdPluginList::gdPluginList(int stackType, Channel *ch) list->scrollbar.color(COLOR_BG_0); list->scrollbar.selection_color(COLOR_BG_1); list->scrollbar.labelcolor(COLOR_BD_1); - list->scrollbar.slider(G_BOX); + list->scrollbar.slider(G_CUSTOM_BORDER_BOX); list->begin(); refreshList(); @@ -101,7 +104,8 @@ gdPluginList::gdPluginList(int stackType, Channel *ch) /* -------------------------------------------------------------------------- */ -gdPluginList::~gdPluginList() { +gdPluginList::~gdPluginList() +{ G_Conf.pluginListX = x(); G_Conf.pluginListY = y(); } @@ -116,8 +120,8 @@ void gdPluginList::cb_addPlugin(Fl_Widget *v, void *p) { ((gdPluginList*)p)->_ /* -------------------------------------------------------------------------- */ -void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) { - +void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) +{ /* note: this callback is fired by gdBrowser. Close its window first, * by calling the parent (pluginList) and telling it to delete its * subwindow (i.e. gdBrowser). */ @@ -138,8 +142,8 @@ void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) { /* -------------------------------------------------------------------------- */ -void gdPluginList::__cb_addPlugin() { - +void gdPluginList::__cb_addPlugin() +{ /* the usual callback that gWindow adds to each subwindow in this case * is not enough, because when we close the browser the plugin list * must be redrawn. We have a special callback, cb_refreshList, which @@ -156,8 +160,8 @@ void gdPluginList::__cb_addPlugin() { /* -------------------------------------------------------------------------- */ -void gdPluginList::refreshList() { - +void gdPluginList::refreshList() +{ /* delete the previous list */ list->clear(); @@ -198,12 +202,12 @@ void gdPluginList::refreshList() { gdPluginListMaster */ if (stackType == PluginHost::MASTER_OUT) { - G_MainWin->inOut->setMasterFxOutFull( + G_MainWin->mainIO->setMasterFxOutFull( G_PluginHost.countPlugins(stackType, ch) > 0); } else if (stackType == PluginHost::MASTER_IN) { - G_MainWin->inOut->setMasterFxInFull( + G_MainWin->mainIO->setMasterFxInFull( G_PluginHost.countPlugins(stackType, ch) > 0); } else { @@ -230,32 +234,24 @@ gdPlugin::gdPlugin(gdPluginList *gdp, Plugin *p, int X, int Y, int W) remove = new gButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm); end(); - if (pPlugin->getStatus() != 1) { // bad state - string l = "* " + pPlugin->getName().toStdString() + " *"; - button->copy_label(l.c_str()); - } - else { - button->copy_label(pPlugin->getName().toStdString().c_str()); - button->callback(cb_openPluginWindow, (void*)this); + button->copy_label(pPlugin->getName().c_str()); + button->callback(cb_openPluginWindow, (void*)this); - program->callback(cb_setProgram, (void*)this); - - for (int i=0; igetNumPrograms(); i++) { - string name = gu_removeFltkChars(pPlugin->getProgramName(i).toStdString()); - program->add(name.c_str()); - } + program->callback(cb_setProgram, (void*)this); - if (program->size() == 0) { - program->add("-- no programs --\0"); - program->deactivate(); - } - else - program->value(pPlugin->getCurrentProgram()); + for (int i=0; igetNumPrograms(); i++) + program->add(gu_removeFltkChars(pPlugin->getProgramName(i)).c_str()); - bypass->callback(cb_setBypass, (void*)this); - bypass->type(FL_TOGGLE_BUTTON); - bypass->value(pPlugin->isBypassed() ? 0 : 1); + if (program->size() == 0) { + program->add("-- no programs --\0"); + program->deactivate(); } + else + program->value(pPlugin->getCurrentProgram()); + + bypass->callback(cb_setBypass, (void*)this); + bypass->type(FL_TOGGLE_BUTTON); + bypass->value(pPlugin->isBypassed() ? 0 : 1); shiftUp->callback(cb_shiftUp, (void*)this); shiftDown->callback(cb_shiftDown, (void*)this); @@ -277,20 +273,20 @@ void gdPlugin::cb_setProgram (Fl_Widget *v, void *p) { ((gdPlugin*)p)->_ /* -------------------------------------------------------------------------- */ -void gdPlugin::__cb_shiftUp() { - +void gdPlugin::__cb_shiftUp() +{ /*nothing to do if there's only one plugin */ if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1) return; - int pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch); + int pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), + pParent->stackType, pParent->ch); if (pluginIndex == 0) // first of the stack, do nothing return; - G_PluginHost.swapPlugin(pluginIndex, pluginIndex - 1, pParent->stackType, - &G_Mixer.mutex_plugins, pParent->ch); + glue_swapPlugins(pParent->ch, pluginIndex, pluginIndex-1, pParent->stackType); pParent->refreshList(); } @@ -298,8 +294,8 @@ void gdPlugin::__cb_shiftUp() { /* -------------------------------------------------------------------------- */ -void gdPlugin::__cb_shiftDown() { - +void gdPlugin::__cb_shiftDown() +{ /*nothing to do if there's only one plugin */ if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1) @@ -311,8 +307,7 @@ void gdPlugin::__cb_shiftDown() { if (pluginIndex == stackSize-1) // last one in the stack, do nothing return; - G_PluginHost.swapPlugin(pluginIndex, pluginIndex + 1, pParent->stackType, - &G_Mixer.mutex_plugins, pParent->ch); + glue_swapPlugins(pParent->ch, pluginIndex, pluginIndex+1, pParent->stackType); pParent->refreshList(); } @@ -320,14 +315,12 @@ void gdPlugin::__cb_shiftDown() { /* -------------------------------------------------------------------------- */ -void gdPlugin::__cb_removePlugin() { - - /* any subwindow linked to the plugin must be destroyed */ +void gdPlugin::__cb_removePlugin() +{ + /* any subwindow linked to the plugin must be destroyed first */ pParent->delSubWindow(pPlugin->getId()); - G_PluginHost.freePlugin(pPlugin->getId(), pParent->stackType, - &G_Mixer.mutex_plugins, pParent->ch); - + glue_freePlugin(pParent->ch, pPlugin->getId(), pParent->stackType); pParent->refreshList(); } @@ -366,7 +359,8 @@ void gdPlugin::__cb_openPluginWindow() /* -------------------------------------------------------------------------- */ -void gdPlugin::__cb_setBypass() { +void gdPlugin::__cb_setBypass() +{ pPlugin->toggleBypass(); } @@ -374,7 +368,8 @@ void gdPlugin::__cb_setBypass() { /* -------------------------------------------------------------------------- */ -void gdPlugin::__cb_setProgram() { +void gdPlugin::__cb_setProgram() +{ pPlugin->setCurrentProgram(program->value()); } diff --git a/src/gui/dialogs/gd_pluginWindow.cpp b/src/gui/dialogs/gd_pluginWindow.cpp index 0c0be5f..d3b7136 100644 --- a/src/gui/dialogs/gd_pluginWindow.cpp +++ b/src/gui/dialogs/gd_pluginWindow.cpp @@ -34,6 +34,7 @@ #include "../../utils/gui.h" #include "../../core/plugin.h" #include "../elems/ge_mixed.h" +#include "../elems/basics/boxtypes.h" #include "gd_pluginWindow.h" @@ -46,7 +47,7 @@ Parameter::Parameter(int paramIndex, Plugin *p, int X, int Y, int W) begin(); label = new gBox(x(), y(), 60, 20); - label->copy_label(pPlugin->getParameterName(paramIndex).toRawUTF8()); + label->copy_label(pPlugin->getParameterName(paramIndex).c_str()); label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); slider = new gSlider(label->x()+label->w()+8, y(), W-200, 20); @@ -55,7 +56,7 @@ Parameter::Parameter(int paramIndex, Plugin *p, int X, int Y, int W) value = new gBox(slider->x()+slider->w()+8, y(), 100, 20); value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); - value->box(G_BOX); + value->box(G_CUSTOM_BORDER_BOX); updateValue(); resizable(slider); @@ -86,8 +87,8 @@ void Parameter::__cb_setValue() void Parameter::updateValue() { - string v = pPlugin->getParameterText(paramIndex).toStdString() + " " + - pPlugin->getParameterLabel(paramIndex).toStdString(); + string v = pPlugin->getParameterText(paramIndex) + " " + + pPlugin->getParameterLabel(paramIndex); value->copy_label(v.c_str()); } @@ -113,7 +114,7 @@ gdPluginWindow::gdPluginWindow(Plugin *p) end(); - label(pPlugin->getName().toRawUTF8()); + label(pPlugin->getName().c_str()); size_range(400, (24*1)+12); resizable(list); diff --git a/src/gui/dialogs/gd_pluginWindowGUI.cpp b/src/gui/dialogs/gd_pluginWindowGUI.cpp index e8ba698..7a5c772 100644 --- a/src/gui/dialogs/gd_pluginWindowGUI.cpp +++ b/src/gui/dialogs/gd_pluginWindowGUI.cpp @@ -79,7 +79,7 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin) Fl::add_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this); - copy_label(pPlugin->getName().toRawUTF8()); + copy_label(pPlugin->getName().c_str()); } diff --git a/src/gui/dialogs/midiIO/midiInputBase.cpp b/src/gui/dialogs/midiIO/midiInputBase.cpp new file mode 100644 index 0000000..256c9d5 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputBase.cpp @@ -0,0 +1,103 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputBase + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/kernelMidi.h" +#include "../../../utils/log.h" +#include "../../elems/midiLearner.h" +#include "midiInputBase.h" + + +extern KernelMidi G_KernelMidi; + + +using std::string; + + +gdMidiInputBase::gdMidiInputBase(int x, int y, int w, int h, const char *title) + : gWindow(x, y, w, h, title) +{ +} + + +/* -------------------------------------------------------------------------- */ + + +gdMidiInputBase::~gdMidiInputBase() +{ + G_KernelMidi.stopMidiLearn(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputBase::stopMidiLearn(geMidiLearner *learner) +{ + G_KernelMidi.stopMidiLearn(); + learner->updateValue(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputBase::__cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l) +{ + *param = msg; + stopMidiLearn(l); + gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputBase::cb_learn(uint32_t msg, void *d) +{ + geMidiLearner::cbData_t *data = (geMidiLearner::cbData_t *) d; + gdMidiInputBase *window = (gdMidiInputBase*) data->window; + geMidiLearner *learner = data->learner; + uint32_t *param = learner->param; + window->__cb_learn(param, msg, learner); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputBase::cb_close(Fl_Widget *w, void *p) { ((gdMidiInputBase*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputBase::__cb_close() +{ + do_callback(); +} diff --git a/src/gui/dialogs/midiIO/midiInputBase.h b/src/gui/dialogs/midiIO/midiInputBase.h new file mode 100644 index 0000000..48f213b --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputBase.h @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputBase + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_INPUT_BASE_H +#define GD_MIDI_INPUT_BASE_H + + +#include "../../elems/ge_window.h" + + +class gdMidiInputBase : public gWindow +{ +protected: + + class gClick *ok; + + void stopMidiLearn(class geMidiLearner *l); + + /* cb_learn + * callback attached to kernelMidi to learn various actions. */ + + static void cb_learn (uint32_t msg, void *data); + inline void __cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l); + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + +public: + + gdMidiInputBase(int x, int y, int w, int h, const char *title); + ~gdMidiInputBase(); +}; + + +#endif diff --git a/src/gui/dialogs/midiIO/midiInputChannel.cpp b/src/gui/dialogs/midiIO/midiInputChannel.cpp new file mode 100644 index 0000000..6bb75e3 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputChannel.cpp @@ -0,0 +1,172 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../../../utils/gui.h" +#include "../../../core/const.h" +#include "../../../core/conf.h" +#include "../../../core/sampleChannel.h" +#ifdef WITH_VST + #include "../../../core/pluginHost.h" + #include "../../../core/plugin.h" +#endif +#include "../../../utils/string.h" +#include "../../elems/ge_mixed.h" +#include "../../elems/midiLearner.h" +#include "../../elems/basics/scroll.h" +#include "midiInputChannel.h" + + +#ifdef WITH_VST +extern PluginHost G_PluginHost; +#endif +extern Conf G_Conf; + + +using std::string; + + +gdMidiInputChannel::gdMidiInputChannel(Channel *ch) + : gdMidiInputBase(G_Conf.midiInputX, G_Conf.midiInputY, G_Conf.midiInputW, + G_Conf.midiInputH, "MIDI Input Setup"), + ch(ch) +{ + string title = "MIDI Input Setup (channel " + gu_itoa(ch->index+1) + ")"; + label(title.c_str()); + size_range(G_DEFAULT_MIDI_INPUT_UI_W, G_DEFAULT_MIDI_INPUT_UI_H); + + enable = new gCheck(8, 8, 120, 20, "enable MIDI input"); + + container = new geScroll(8, enable->y()+enable->h()+4, w()-16, h()-70); + container->begin(); + + addChannelLearners(); +#ifdef WITH_VST + addPluginLearners(); +#endif + + container->end(); + + ok = new gButton(w()-88, container->y()+container->h()+8, 80, 20, "Close"); + ok->callback(cb_close, (void*)this); + + enable->value(ch->midiIn); + enable->callback(cb_enable, (void*)this); + + resizable(container); + + gu_setFavicon(this); + set_modal(); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +gdMidiInputChannel::~gdMidiInputChannel() +{ + G_Conf.midiInputX = x(); + G_Conf.midiInputY = y(); + G_Conf.midiInputW = w(); + G_Conf.midiInputH = h(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputChannel::addChannelLearners() +{ + Fl_Pack *pack = new Fl_Pack(container->x(), container->y(), LEARNER_WIDTH, 200); + pack->spacing(4); + pack->begin(); + + gBox *header = new gBox(0, 0, LEARNER_WIDTH, 20, "channel"); + header->box(FL_BORDER_BOX); + new geMidiLearner(0, 0, LEARNER_WIDTH, "key press", cb_learn, &ch->midiInKeyPress); + new geMidiLearner(0, 0, LEARNER_WIDTH, "key release", cb_learn, &ch->midiInKeyRel); + new geMidiLearner(0, 0, LEARNER_WIDTH, "key kill", cb_learn, &ch->midiInKill); + new geMidiLearner(0, 0, LEARNER_WIDTH, "arm", cb_learn, &ch->midiInArm); + new geMidiLearner(0, 0, LEARNER_WIDTH, "mute", cb_learn, &ch->midiInMute); + new geMidiLearner(0, 0, LEARNER_WIDTH, "solo", cb_learn, &ch->midiInSolo); + new geMidiLearner(0, 0, LEARNER_WIDTH, "volume", cb_learn, &ch->midiInVolume); + if (ch->type == CHANNEL_SAMPLE) { + new geMidiLearner(0, 0, LEARNER_WIDTH, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); + new geMidiLearner(0, 0, LEARNER_WIDTH, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); + } + + pack->end(); +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST + +void gdMidiInputChannel::addPluginLearners() +{ + vector *plugins = G_PluginHost.getStack(PluginHost::CHANNEL, ch); + for (unsigned i=0; isize(); i++) { + + Fl_Pack *pack = new Fl_Pack(container->x() + ((i + 1) * (LEARNER_WIDTH + 8)), + container->y(), LEARNER_WIDTH, 200); + pack->spacing(4); + pack->begin(); + + Plugin *plugin = plugins->at(i); + + gBox *header = new gBox(0, 0, LEARNER_WIDTH, 20, plugin->getName().c_str()); + header->box(FL_BORDER_BOX); + + for (int k=0; kgetNumParameters(); k++) + new geMidiLearner(0, 0, LEARNER_WIDTH, plugin->getParameterName(k).c_str(), + cb_learn, &plugin->midiInParams.at(k)); + + pack->end(); + } +} + +#endif + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiInputChannel*)p)->__cb_enable(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputChannel::__cb_enable() +{ + ch->midiIn = enable->value(); +} diff --git a/src/gui/dialogs/midiIO/midiInputChannel.h b/src/gui/dialogs/midiIO/midiInputChannel.h new file mode 100644 index 0000000..462a158 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputChannel.h @@ -0,0 +1,68 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_INPUT_CHANNEL_H +#define GD_MIDI_INPUT_CHANNEL_H + + +#include "midiInputBase.h" + + +class gdMidiInputChannel : public gdMidiInputBase +{ +private: + + static const int LEARNER_WIDTH = 284; + + class Channel *ch; + + class geScroll *container; + class gCheck *enable; + + //gVector items; // plugins parameters + + static void cb_enable (Fl_Widget *w, void *p); + inline void __cb_enable(); + + void addChannelLearners(); + +#ifdef WITH_VST + + void addPluginLearners(); + +#endif + +public: + + gdMidiInputChannel(class Channel *ch); + ~gdMidiInputChannel(); +}; + + +#endif diff --git a/src/gui/dialogs/midiIO/midiInputMaster.cpp b/src/gui/dialogs/midiIO/midiInputMaster.cpp new file mode 100644 index 0000000..e7a8def --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputMaster.cpp @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputMaster + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../utils/gui.h" +#include "../../../core/conf.h" +#include "../../elems/ge_mixed.h" +#include "../../elems/midiLearner.h" +#include "midiInputMaster.h" + + +extern Conf G_Conf; + + +gdMidiInputMaster::gdMidiInputMaster() + : gdMidiInputBase(0, 0, 300, 256, "MIDI Input Setup (global)") +{ + set_modal(); + + new geMidiLearner(8, 8, w()-16, "rewind", &cb_learn, &G_Conf.midiInRewind); + new geMidiLearner(8, 32, w()-16, "play/stop", &cb_learn, &G_Conf.midiInStartStop); + new geMidiLearner(8, 56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec); + new geMidiLearner(8, 80, w()-16, "input recording", &cb_learn, &G_Conf.midiInInputRec); + new geMidiLearner(8, 104, w()-16, "metronome", &cb_learn, &G_Conf.midiInMetronome); + new geMidiLearner(8, 128, w()-16, "input volume", &cb_learn, &G_Conf.midiInVolumeIn); + new geMidiLearner(8, 152, w()-16, "output volume", &cb_learn, &G_Conf.midiInVolumeOut); + new geMidiLearner(8, 176, w()-16, "sequencer ×2", &cb_learn, &G_Conf.midiInBeatDouble); + new geMidiLearner(8, 200, w()-16, "sequencer ÷2", &cb_learn, &G_Conf.midiInBeatHalf); + ok = new gButton(w()-88, 228, 80, 20, "Close"); + + ok->callback(cb_close, (void*)this); + + gu_setFavicon(this); + show(); +} diff --git a/src/gui/dialogs/midiIO/midiInputMaster.h b/src/gui/dialogs/midiIO/midiInputMaster.h new file mode 100644 index 0000000..55a4cd5 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiInputMaster.h @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiInputMaster + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_INPUT_MASTER_H +#define GD_MIDI_INPUT_MASTER_H + + +#include "midiInputBase.h" + + +class gdMidiInputMaster : public gdMidiInputBase +{ +public: + + gdMidiInputMaster(); +}; + + +#endif diff --git a/src/gui/dialogs/midiIO/midiOutputBase.cpp b/src/gui/dialogs/midiIO/midiOutputBase.cpp new file mode 100644 index 0000000..d8afd77 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputBase.cpp @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiOutput + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../utils/log.h" +#include "../../elems/midiLearner.h" +#include "midiOutputBase.h" + + +extern KernelMidi G_KernelMidi; + + +gdMidiOutputBase::gdMidiOutputBase(int w, int h) + : gWindow(w, h, "Midi Output Setup") +{ +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::stopMidiLearn(geMidiLearner *learner) +{ + G_KernelMidi.stopMidiLearn(); + learner->updateValue(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::__cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l) +{ + *param = msg; + stopMidiLearn(l); + gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::cb_learn(uint32_t msg, void *d) +{ + geMidiLearner::cbData_t *data = (geMidiLearner::cbData_t*) d; + gdMidiOutputBase *window = (gdMidiOutputBase*) data->window; + geMidiLearner *learner = data->learner; + uint32_t *param = learner->param; + window->__cb_learn(param, msg, learner); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputBase*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::__cb_close() +{ + do_callback(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::cb_enableLightning(Fl_Widget *w, void *p) +{ + ((gdMidiOutputBase*)p)->__cb_enableLightning(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::__cb_enableLightning() {} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputBase::setTitle(int chanNum) +{ + char title[64]; + sprintf(title, "MIDI Output Setup (channel %d)", chanNum); + copy_label(title); +} diff --git a/src/gui/dialogs/midiIO/midiOutputBase.h b/src/gui/dialogs/midiIO/midiOutputBase.h new file mode 100644 index 0000000..fd639d4 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputBase.h @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiOutput + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_OUTPUT_BASE_H +#define GD_MIDI_OUTPUT_BASE_H + + +#include +#include "../../elems/ge_window.h" + + +/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI +output master is managed by the configuration window, hence gdMidiOutput deals +only with channels. + +Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set. +In addition MidiOutputMidiCh has the MIDI message output box. */ + +/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another +parent class gdMidiIO to inherit from */ + +class gdMidiOutputBase : public gWindow +{ +protected: + + class gClick *close; + class gCheck *enableLightning; + + void stopMidiLearn(class geMidiLearner *l); + + /* cb_learn + * callback attached to kernelMidi to learn various actions. */ + + static void cb_learn (uint32_t msg, void *data); + inline void __cb_learn(uint32_t *param, uint32_t msg, class geMidiLearner *l); + + /* cb_close + close current window. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + + /* cb_enableLightning + enable MIDI lightning output. */ + + static void cb_enableLightning (Fl_Widget *w, void *p); + inline void __cb_enableLightning(); + + /* setTitle + * set window title. */ + + void setTitle(int chanNum); + +public: + + gdMidiOutputBase(int w, int h); +}; + + +#endif diff --git a/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp b/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp new file mode 100644 index 0000000..08954dd --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp @@ -0,0 +1,119 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiOutputMidiCh + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/midiChannel.h" +#include "../../../utils/gui.h" +#include "../../elems/ge_mixed.h" +#include "../../elems/midiLearner.h" +#include "../../elems/mainWindow/keyboard/channel.h" +#include "midiOutputMidiCh.h" + + +gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch) + : gdMidiOutputBase(300, 168), ch(ch) +{ + setTitle(ch->index+1); + begin(); + + enableOut = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output"); + chanListOut = new gChoice(w()-108, y()+8, 100, 20); + + enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output"); + new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); + new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); + new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); + + close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); + + end(); + + chanListOut->add("Channel 1"); + chanListOut->add("Channel 2"); + chanListOut->add("Channel 3"); + chanListOut->add("Channel 4"); + chanListOut->add("Channel 5"); + chanListOut->add("Channel 6"); + chanListOut->add("Channel 7"); + chanListOut->add("Channel 8"); + chanListOut->add("Channel 9"); + chanListOut->add("Channel 10"); + chanListOut->add("Channel 11"); + chanListOut->add("Channel 12"); + chanListOut->add("Channel 13"); + chanListOut->add("Channel 14"); + chanListOut->add("Channel 15"); + chanListOut->add("Channel 16"); + chanListOut->value(0); + + if (ch->midiOut) + enableOut->value(1); + else + chanListOut->deactivate(); + + if (ch->midiOutL) + enableLightning->value(1); + + chanListOut->value(ch->midiOutChan); + + enableOut->callback(cb_enableChanList, (void*)this); + close->callback(cb_close, (void*)this); + + set_modal(); + gu_setFavicon(this); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::cb_close (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); } +void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::__cb_enableChanList() +{ + enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::__cb_close() +{ + ch->midiOut = enableOut->value(); + ch->midiOutChan = chanListOut->value(); + ch->midiOutL = enableLightning->value(); + ch->guiChannel->update(); + do_callback(); +} diff --git a/src/gui/dialogs/midiIO/midiOutputMidiCh.h b/src/gui/dialogs/midiIO/midiOutputMidiCh.h new file mode 100644 index 0000000..a0deb21 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputMidiCh.h @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiOutputMidiCh + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_OUTPUT_MIDI_CH_H +#define GD_MIDI_OUTPUT_MIDI_CH_H + + +#include "midiOutputBase.h" + + +class gdMidiOutputMidiCh : public gdMidiOutputBase +{ +private: + + static void cb_enableChanList (Fl_Widget *w, void *p); + inline void __cb_enableChanList(); + + /* __cb_close + override parent method, we need to do more stuff on close. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + + class gCheck *enableOut; + class gChoice *chanListOut; + + class MidiChannel *ch; + +public: + + gdMidiOutputMidiCh(class MidiChannel *ch); +}; + + +#endif diff --git a/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp b/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp new file mode 100644 index 0000000..4cbe682 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiOutputSampleCh + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/sampleChannel.h" +#include "../../../utils/gui.h" +#include "../../elems/ge_mixed.h" +#include "../../elems/midiLearner.h" +#include "midiOutputSampleCh.h" + + +gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch) + : gdMidiOutputBase(300, 140), ch(ch) +{ + setTitle(ch->index+1); + + enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output"); + new geMidiLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); + new geMidiLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); + new geMidiLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); + + close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); + close->callback(cb_close, (void*)this); + + enableLightning->value(ch->midiOutL); + enableLightning->callback(cb_enableLightning, (void*)this); + + set_modal(); + gu_setFavicon(this); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputSampleCh::__cb_close() +{ + ch->midiOutL = enableLightning->value(); + do_callback(); +} diff --git a/src/gui/dialogs/midiIO/midiOutputSampleCh.h b/src/gui/dialogs/midiIO/midiOutputSampleCh.h new file mode 100644 index 0000000..b229ca8 --- /dev/null +++ b/src/gui/dialogs/midiIO/midiOutputSampleCh.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiOutputSampleCh + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GD_MIDI_OUTPUT_SAMPLE_CH_H +#define GD_MIDI_OUTPUT_SAMPLE_CH_H + + +#include "midiOutputBase.h" + + +class gdMidiOutputSampleCh : public gdMidiOutputBase +{ +private: + + class SampleChannel *ch; + + /* __cb_close + override parent method, we need to do more stuff on close. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + +public: + + gdMidiOutputSampleCh(class SampleChannel *ch); +}; + +#endif diff --git a/src/gui/elems/actionEditor.cpp b/src/gui/elems/actionEditor.cpp index 4a88413..065860d 100644 --- a/src/gui/elems/actionEditor.cpp +++ b/src/gui/elems/actionEditor.cpp @@ -35,7 +35,7 @@ #include "../../utils/log.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_actionEditor.h" -#include "ge_keyboard.h" +#include "mainWindow/keyboard/keyboard.h" #include "actionEditor.h" @@ -591,6 +591,8 @@ void gAction::addAction() //gu_log("action added, [%d]\n", frame_a); } + parent->chan->hasActions = true; + G_Recorder.sortActions(); index++; // important! @@ -606,11 +608,17 @@ void gAction::delAction() * actions. */ if (ch->mode == SINGLE_PRESS) { - G_Recorder.deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false); - G_Recorder.deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false); + G_Recorder.deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, + false, &G_Mixer.mutex_recs); + G_Recorder.deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, + false, &G_Mixer.mutex_recs); } else - G_Recorder.deleteAction(parent->chan->index, frame_a, type, false); + G_Recorder.deleteAction(parent->chan->index, frame_a, type, false, + &G_Mixer.mutex_recs); + + parent->chan->hasActions = G_Recorder.hasActions(parent->chan->index); + /* restore the initial cursor shape, in case you delete an action and * the double arrow (for resizing) is displayed */ @@ -648,6 +656,8 @@ void gAction::moveAction(int frame_a) G_Recorder.rec(parent->chan->index, ACTION_KEYREL, frame_b); } + parent->chan->hasActions = true; + G_Recorder.sortActions(); } diff --git a/src/gui/elems/basics/boxtypes.cpp b/src/gui/elems/basics/boxtypes.cpp new file mode 100644 index 0000000..547d1aa --- /dev/null +++ b/src/gui/elems/basics/boxtypes.cpp @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * boxtypes + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../../../core/const.h" +#include "boxtypes.h" + + +void g_customBorderBox(int x, int y, int w, int h, Fl_Color c) +{ + fl_color(c); + fl_rectf(x, y, w, h); + fl_color(COLOR_BD_0); + fl_rect(x, y, w, h); +} + + +void g_customUpBox(int x, int y, int w, int h, Fl_Color c) +{ + fl_color(COLOR_BG_0); + fl_rectf(x, y, w, h); + fl_color(COLOR_BG_0); + fl_rect(x, y, w, h); +} + + +void g_customDownBox(int x, int y, int w, int h, Fl_Color c) +{ + fl_color(c); + fl_rectf(x, y, w, h); + fl_color(COLOR_BG_0); + fl_rect(x, y, w, h); +} diff --git a/src/gui/elems/basics/boxtypes.h b/src/gui/elems/basics/boxtypes.h new file mode 100644 index 0000000..d717c86 --- /dev/null +++ b/src/gui/elems/basics/boxtypes.h @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * boxtypes + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef __BOXTYPES_H__ +#define __BOXTYPES_H__ + + +#include + + +#define G_CUSTOM_BORDER_BOX FL_FREE_BOXTYPE +#define G_CUSTOM_UP_BOX (Fl_Boxtype)(FL_FREE_BOXTYPE + 1) +#define G_CUSTOM_DOWN_BOX (Fl_Boxtype)(FL_FREE_BOXTYPE + 3) + + +void g_customBorderBox(int x, int y, int w, int h, Fl_Color c); +void g_customUpBox (int x, int y, int w, int h, Fl_Color c); +void g_customDownBox (int x, int y, int w, int h, Fl_Color c); + + +#endif diff --git a/src/gui/elems/basics/scroll.cpp b/src/gui/elems/basics/scroll.cpp new file mode 100644 index 0000000..9cee240 --- /dev/null +++ b/src/gui/elems/basics/scroll.cpp @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * geScroll + * Custom scroll with nice scrollbars and something else. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/const.h" +#include "boxtypes.h" +#include "scroll.h" + + +geScroll::geScroll(int x, int y, int w, int h, int t) + : Fl_Scroll(x, y, w, h) +{ + type(t); + + scrollbar.color(COLOR_BG_0); + scrollbar.selection_color(COLOR_BG_1); + scrollbar.labelcolor(COLOR_BD_1); + scrollbar.slider(G_CUSTOM_BORDER_BOX); + + hscrollbar.color(COLOR_BG_0); + hscrollbar.selection_color(COLOR_BG_1); + hscrollbar.labelcolor(COLOR_BD_1); + hscrollbar.slider(G_CUSTOM_BORDER_BOX); +} diff --git a/src/gui/elems/basics/scroll.h b/src/gui/elems/basics/scroll.h new file mode 100644 index 0000000..b122d44 --- /dev/null +++ b/src/gui/elems/basics/scroll.h @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * geScroll + * Custom scroll with nice scrollbars and something else. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef __GE_SCROLL_H__ +#define __GE_SCROLL_H__ + + +#include + + +class geScroll : public Fl_Scroll +{ +public: + + geScroll(int x, int y, int w, int h, int type=Fl_Scroll::BOTH); +}; + + +#endif diff --git a/src/gui/elems/browser.cpp b/src/gui/elems/browser.cpp new file mode 100644 index 0000000..812aaba --- /dev/null +++ b/src/gui/elems/browser.cpp @@ -0,0 +1,188 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_browser + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../core/const.h" +#include "../../utils/string.h" +#include "../dialogs/gd_browser.h" +#include "../elems/ge_mixed.h" +#include "basics/boxtypes.h" +#include "browser.h" + + +geBrowser::geBrowser(int x, int y, int w, int h) + : Fl_File_Browser(x, y, w, h), + showHiddenFiles(false) +{ + box(G_CUSTOM_BORDER_BOX); + textsize(GUI_FONT_SIZE_BASE); + textcolor(COLOR_TEXT_0); + selection_color(COLOR_BG_1); + color(COLOR_BG_0); + type(FL_SELECT_BROWSER); + + this->scrollbar.color(COLOR_BG_0); + this->scrollbar.selection_color(COLOR_BG_1); + this->scrollbar.labelcolor(COLOR_BD_1); + this->scrollbar.slider(G_CUSTOM_BORDER_BOX); + + this->hscrollbar.color(COLOR_BG_0); + this->hscrollbar.selection_color(COLOR_BG_1); + this->hscrollbar.labelcolor(COLOR_BD_1); + this->hscrollbar.slider(G_CUSTOM_BORDER_BOX); + + take_focus(); // let it have focus on startup +} + + +/* -------------------------------------------------------------------------- */ + + +void geBrowser::toggleHiddenFiles() +{ + showHiddenFiles = !showHiddenFiles; + loadDir(currentDir); +} + + +/* -------------------------------------------------------------------------- */ + + +void geBrowser::loadDir(const string &dir) +{ + currentDir = dir; + load(currentDir.c_str()); + + /* Clean up unwanted elements. Hide "../" first, it just screws up things. + Also remove hidden files, if requested. */ + + for (int i=size(); i>=0; i--) { + if (text(i) == nullptr) + continue; + if (strcmp(text(i), "../") == 0 || (!showHiddenFiles && strncmp(text(i), ".", 1) == 0)) + remove(i); + } +} + + +/* -------------------------------------------------------------------------- */ + +int geBrowser::handle(int e) +{ + int ret = Fl_File_Browser::handle(e); + switch (e) { + case FL_FOCUS: + case FL_UNFOCUS: + ret = 1; // enables receiving Keyboard events + break; + case FL_KEYDOWN: // keyboard + if (Fl::event_key(FL_Down)) + select(value() + 1); + else + if (Fl::event_key(FL_Up)) + select(value() - 1); + else + if (Fl::event_key(FL_Enter)) + ((gdBaseBrowser*) parent())->fireCallback(); + ret = 1; + break; + case FL_PUSH: // mouse + if (Fl::event_clicks() > 0) // double click + ((gdBaseBrowser*) parent())->fireCallback(); + ret = 1; + break; + case FL_RELEASE: // mouse + /* nasty trick to keep the selection on mouse release */ + if (value() > 1) { + select(value() - 1); + select(value() + 1); + } + else { + select(value() + 1); + select(value() - 1); + } + ret = 1; + break; + } + return ret; +} + +/* -------------------------------------------------------------------------- */ + + +string geBrowser::getCurrentDir() +{ + return normalize(gu_getRealPath(currentDir)); +} + + +/* -------------------------------------------------------------------------- */ + + +string geBrowser::getSelectedItem(bool fullPath) +{ + if (!fullPath) // no full path requested? return the selected text + return normalize(text(value())); + else + if (value() == 0) // no rows selected? return current directory + return normalize(currentDir); + else + return normalize(gu_getRealPath(currentDir + G_SLASH + normalize(text(value())))); +} + + +/* -------------------------------------------------------------------------- */ + + +void geBrowser::preselect(int pos, int line) +{ + position(pos); + select(line); +} + + +/* -------------------------------------------------------------------------- */ + + +string geBrowser::normalize(const string &s) +{ + string out = s; + + /* If string ends with G_SLASH, remove it. Don't do it if has length > 1, it + means that the string is just '/'. Note: our crappy version of Clang doesn't + seem to support std::string::back() */ + +#ifdef __APPLE__ + if (out[out.length() - 1] == G_SLASH && out.length() > 1) +#else + if (out.back() == G_SLASH && out.length() > 1) +#endif + + out = out.substr(0, out.size()-1); + return out; +} diff --git a/src/gui/elems/browser.h b/src/gui/elems/browser.h new file mode 100644 index 0000000..4515dbf --- /dev/null +++ b/src/gui/elems/browser.h @@ -0,0 +1,77 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_browser + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_BROWSER_H +#define GE_BROWSER_H + + +#include +#include + + +using std::string; + + +class geBrowser : public Fl_File_Browser +{ +private: + + string currentDir; + bool showHiddenFiles; + + /* normalize + * Make sure the string never ends with a trailing slash. */ + + string normalize(const string &s); + +public: + + geBrowser(int x, int y, int w, int h); + + void toggleHiddenFiles(); + + /* init + * Initialize browser and show 'dir' as initial directory. */ + + void loadDir(const string &dir); + + /* getSelectedItem + * Return the full path or just the displayed name of the i-th selected item. + * Always with the trailing slash! */ + + string getSelectedItem(bool fullPath=true); + + string getCurrentDir(); + + void preselect(int position, int line); + + int handle(int e); +}; + +#endif diff --git a/src/gui/elems/channel.cpp b/src/gui/elems/channel.cpp deleted file mode 100644 index a33f121..0000000 --- a/src/gui/elems/channel.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_channel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/mixer.h" -#include "../../core/conf.h" -#include "../../core/channel.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/graphics.h" -#include "../../core/pluginHost.h" -#include "../../utils/gui.h" -#include "../../glue/channel.h" -#include "../../glue/main.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_pluginList.h" -#include "ge_column.h" -#include "channelButton.h" -#include "channel.h" - - -extern Mixer G_Mixer; -extern Conf G_Conf; -extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *G_MainWin; - - -geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch) - : Fl_Group(X, Y, W, H, NULL), - ch (ch), - type (type) -{ -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::cb_arm(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_arm(); } -void geChannel::cb_mute(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_mute(); } -void geChannel::cb_solo(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_solo(); } -void geChannel::cb_changeVol(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_changeVol(); } -#ifdef WITH_VST -void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_openFxWindow(); } -#endif - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::__cb_arm() -{ - glue_toggleArm(ch, true); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::__cb_mute() -{ - glue_setMute(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::__cb_solo() -{ - solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::__cb_changeVol() -{ - glue_setChanVol(ch, vol->value()); -} - - -/* -------------------------------------------------------------------------- */ - - -#ifdef WITH_VST -void geChannel::__cb_openFxWindow() -{ - gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); -} -#endif - - -/* -------------------------------------------------------------------------- */ - - -int geChannel::keyPress(int e) -{ - return handleKey(e, ch->key); -} - - -/* -------------------------------------------------------------------------- */ - - - -int geChannel::getColumnIndex() -{ - return ((gColumn*)parent())->getIndex(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::blink() -{ - if (gu_getBlinker() > 6) - mainButton->setPlayMode(); - else - mainButton->setDefaultMode(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::setColorsByStatus(int playStatus, int recStatus) -{ - switch (playStatus) { - case STATUS_OFF: - case STATUS_EMPTY: - mainButton->setDefaultMode(); - button->imgOn = channelPlay_xpm; - button->imgOff = channelStop_xpm; - button->redraw(); - break; - case STATUS_PLAY: - mainButton->setPlayMode(); - button->imgOn = channelStop_xpm; - button->imgOff = channelPlay_xpm; - button->redraw(); - break; - case STATUS_WAIT: - blink(); - break; - case STATUS_ENDING: - mainButton->setEndingMode(); - break; - } - - switch (recStatus) { - case REC_WAITING: - blink(); - break; - case REC_ENDING: - mainButton->setEndingMode(); - break; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannel::packWidgets() -{ - /* Count visible widgets and resize mainButton according to how many widgets - are visible. */ - - int visibles = 0; - for (int i=0; isize(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; ivisible()) - continue; - for (int k=i-1; k>=0; k--) // Get the first visible item prior to i - if (child(k)->visible()) { - p = k; - break; - } - child(i)->position(child(p)->x() + child(p)->w() + 4, y()); - } - - init_sizes(); // Resets the internal array of widget sizes and positions -} - - -/* -------------------------------------------------------------------------- */ - - -int geChannel::handleKey(int e, int key) -{ - int ret; - if (e == FL_KEYDOWN && button->value()) // key already pressed! skip it - ret = 1; - else - if (Fl::event_key() == key && !button->value()) { - button->take_focus(); // move focus to this button - button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state - button->do_callback(); // invoke the button's callback - ret = 1; - } - else - ret = 0; - - if (Fl::event_key() == key) - button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state - - return ret; -} diff --git a/src/gui/elems/channel.h b/src/gui/elems/channel.h deleted file mode 100644 index 33dc00d..0000000 --- a/src/gui/elems/channel.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_channel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_CHANNEL_H -#define GE_CHANNEL_H - - -#include - - -class geChannel : public Fl_Group -{ -protected: - - /* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of - pixels to shrink sampleButton. */ - -#ifdef WITH_VST - static const int BREAK_READ_ACTIONS = 240; - static const int BREAK_MODE_BOX = 216; - static const int BREAK_FX = 192; - static const int BREAK_ARM = 168; -#else - static const int BREAK_READ_ACTIONS = 216; - static const int BREAK_MODE_BOX = 192; - static const int BREAK_ARM = 168; -#endif - - static void cb_arm (Fl_Widget *v, void *p); - static void cb_mute (Fl_Widget *v, void *p); - static void cb_solo (Fl_Widget *v, void *p); - static void cb_changeVol (Fl_Widget *v, void *p); -#ifdef WITH_VST - static void cb_openFxWindow(Fl_Widget *v, void *p); -#endif - - inline void __cb_mute(); - inline void __cb_arm(); - inline void __cb_solo(); - inline void __cb_changeVol(); -#ifdef WITH_VST - inline void __cb_openFxWindow(); -#endif - - /* blink - * blink button when channel is in wait/ending status. */ - - void blink(); - - /* setColorByStatus - * update colors depending on channel status. */ - - void setColorsByStatus(int playStatus, int recStatus); - - /* handleKey - * method wrapped by virtual handle(int e). */ - - int handleKey(int e, int key); - - /* packWidgets - Spread widgets across available space. */ - - void packWidgets(); - -public: - - geChannel(int x, int y, int w, int h, int type, class Channel *ch); - - /* reset - * reset channel to initial status. */ - - virtual void reset() = 0; - - /* update - * update the label of sample button and everything else such as 'R' - * button, key box and so on, according to global values. */ - - virtual void update() = 0; - - /* refresh - * update graphics. */ - - virtual void refresh() = 0; - - /* keypress - * what to do when the corresponding key is pressed. */ - - int keyPress(int event); - - /* getColumnIndex - * return the numeric index of the column in which this channel is - * located. */ - - int getColumnIndex(); - - class Channel *ch; - - class gButton *button; - class gStatus *status; - class gClick *arm; - class geChannelButton *mainButton; - class gClick *mute; - class gClick *solo; - class gDial *vol; -#ifdef WITH_VST - class gFxButton *fx; -#endif - - int type; -}; - - -#endif diff --git a/src/gui/elems/channelButton.cpp b/src/gui/elems/channelButton.cpp deleted file mode 100644 index 69d262d..0000000 --- a/src/gui/elems/channelButton.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_channelButton - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/const.h" -#include "../../utils/fs.h" -#include "channelButton.h" - - -using std::string; - - -geChannelButton::geChannelButton(int x, int y, int w, int h, const char *l) - : gClick(x, y, w, h, l), key("") {} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setKey(const string &k) -{ - key = k; -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setKey(int k) -{ - if (k == 0) - key = ""; - else { - // FIXME - this crap won't work with unicode/utf-8 - char c = (char) k; - key = c; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::draw() -{ - gClick::draw(); - - if (key == "") - return; - - /* draw background */ - - fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0); - - /* draw key */ - - fl_color(COLOR_TEXT_0); - fl_font(FL_HELVETICA, 11); - fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setInputRecordMode() -{ - bgColor0 = COLOR_BG_3; -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setActionRecordMode() -{ - bgColor0 = COLOR_BG_4; - txtColor = COLOR_TEXT_0; -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setDefaultMode(const char *l) -{ - bgColor0 = COLOR_BG_0; - bdColor = COLOR_BD_0; - txtColor = COLOR_TEXT_0; - if (l) - label(l); -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setPlayMode() -{ - bgColor0 = COLOR_BG_2; - bdColor = COLOR_BD_1; - txtColor = COLOR_TEXT_1; -} - - -/* -------------------------------------------------------------------------- */ - - -void geChannelButton::setEndingMode() -{ - bgColor0 = COLOR_BD_0; -} diff --git a/src/gui/elems/channelButton.h b/src/gui/elems/channelButton.h deleted file mode 100644 index da08cd8..0000000 --- a/src/gui/elems/channelButton.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_channelButton - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_CHANNEL_BUTTON_H -#define GE_CHANNEL_BUTTON_H - - -#include "ge_mixed.h" - - -using std::string; - - -class geChannelButton : public gClick -{ -private: - - string key; - -public: - - geChannelButton(int x, int y, int w, int h, const char *l=0); - - virtual int handle(int e) = 0; - - void draw(); - void setKey(const string &k); - void setKey(int k); - void setPlayMode(); - void setEndingMode(); - void setDefaultMode(const char *l=0); - void setInputRecordMode(); - void setActionRecordMode(); -}; - - -#endif diff --git a/src/gui/elems/envelopeEditor.cpp b/src/gui/elems/envelopeEditor.cpp index 7ade209..796a3fe 100644 --- a/src/gui/elems/envelopeEditor.cpp +++ b/src/gui/elems/envelopeEditor.cpp @@ -36,7 +36,7 @@ #include "../../core/mixer.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" -#include "ge_keyboard.h" +#include "mainWindow/keyboard/keyboard.h" #include "envelopeEditor.h" @@ -194,6 +194,7 @@ int geEnvelopeEditor::handle(int e) { G_Recorder.rec(pParent->chan->index, type, 0, 0, 1.0f); addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1); G_Recorder.rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f); + pParent->chan->hasActions = true; } /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */ @@ -202,6 +203,7 @@ int geEnvelopeEditor::handle(int e) { float value = (my - h() + 8) / (float) (1 - h() + 8); addPoint(frame, 0, value, mx, my); G_Recorder.rec(pParent->chan->index, type, frame, 0, value); + pParent->chan->hasActions = true; G_Recorder.sortActions(); sortPoints(); } @@ -219,11 +221,14 @@ int geEnvelopeEditor::handle(int e) { if (selectedPoint != -1) { if (selectedPoint == 0 || (unsigned) selectedPoint == points.size()-1) { G_Recorder.clearAction(pParent->chan->index, type); + pParent->chan->hasActions = G_Recorder.hasActions(pParent->chan->index); points.clear(); } else { - G_Recorder.deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false); - G_Recorder.sortActions(); + G_Recorder.deleteAction(pParent->chan->index, + points.at(selectedPoint).frame, type, false, &G_Mixer.mutex_recs); + pParent->chan->hasActions = G_Recorder.hasActions(pParent->chan->index); + G_Recorder.sortActions(); points.erase(points.begin() + selectedPoint); } G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow @@ -259,11 +264,14 @@ int geEnvelopeEditor::handle(int e) { /* delete previous point and record a new one */ - G_Recorder.deleteAction(pParent->chan->index, points.at(draggedPoint).frame, type, false); + G_Recorder.deleteAction(pParent->chan->index, + points.at(draggedPoint).frame, type, false, &G_Mixer.mutex_recs); + pParent->chan->hasActions = G_Recorder.hasActions(pParent->chan->index); if (range == RANGE_FLOAT) { float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8); G_Recorder.rec(pParent->chan->index, type, newFrame, 0, value); + pParent->chan->hasActions = true; } else { /// TODO diff --git a/src/gui/elems/ge_browser.cpp b/src/gui/elems/ge_browser.cpp deleted file mode 100644 index 9ae3235..0000000 --- a/src/gui/elems/ge_browser.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_browser - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include -#include "../../core/const.h" -#include "../../utils/fs.h" -#include "../../utils/string.h" -#include "../../utils/log.h" -#include "../dialogs/gd_browser.h" -#include "ge_browser.h" - - -gBrowser::gBrowser(int x, int y, int w, int h) - : Fl_File_Browser(x, y, w, h) -{ - box(G_BOX); - textsize(GUI_FONT_SIZE_BASE); - textcolor(COLOR_TEXT_0); - selection_color(COLOR_BG_1); - color(COLOR_BG_0); - type(FL_SELECT_BROWSER); - - this->scrollbar.color(COLOR_BG_0); - this->scrollbar.selection_color(COLOR_BG_1); - this->scrollbar.labelcolor(COLOR_BD_1); - this->scrollbar.slider(G_BOX); - - this->hscrollbar.color(COLOR_BG_0); - this->hscrollbar.selection_color(COLOR_BG_1); - this->hscrollbar.labelcolor(COLOR_BD_1); - this->hscrollbar.slider(G_BOX); - - take_focus(); // let it have focus on startup -} - - -/* -------------------------------------------------------------------------- */ - - -void gBrowser::loadDir(const string &dir) -{ - currentDir = dir; - load(currentDir.c_str()); - - /* hide "../", it just screws up things */ - - if (text(1) != NULL && strcmp(text(1), "../") == 0) - remove(1); -} - - -/* -------------------------------------------------------------------------- */ - -int gBrowser::handle(int e) -{ - int ret = Fl_File_Browser::handle(e); - switch (e) { - case FL_FOCUS: - case FL_UNFOCUS: - ret = 1; // enables receiving Keyboard events - break; - case FL_KEYDOWN: // keyboard - if (Fl::event_key(FL_Down)) - select(value() + 1); - else - if (Fl::event_key(FL_Up)) - select(value() - 1); - else - if (Fl::event_key(FL_Enter)) - ((gdBaseBrowser*) parent())->fireCallback(); - ret = 1; - break; - case FL_PUSH: // mouse - if (Fl::event_clicks() > 0) // double click - ((gdBaseBrowser*) parent())->fireCallback(); - ret = 1; - break; - case FL_RELEASE: // mouse - /* nasty trick to keep the selection on mouse release */ - if (value() > 1) { - select(value() - 1); - select(value() + 1); - } - else { - select(value() + 1); - select(value() - 1); - } - ret = 1; - break; - } - return ret; -} - -/* -------------------------------------------------------------------------- */ - - -string gBrowser::getCurrentDir() -{ - return normalize(gu_getRealPath(currentDir)); -} - - -/* -------------------------------------------------------------------------- */ - - -string gBrowser::getSelectedItem(bool fullPath) -{ - if (!fullPath) // no full path requested? return the selected text - return normalize(text(value())); - else - if (value() == 0) // no rows selected? return current directory - return normalize(currentDir); - else - return normalize(gu_getRealPath(currentDir + G_SLASH + normalize(text(value())))); -} - - -/* -------------------------------------------------------------------------- */ - - -void gBrowser::preselect(int pos, int line) -{ - position(pos); - select(line); -} - - -/* -------------------------------------------------------------------------- */ - - -string gBrowser::normalize(const string &s) -{ - string out = s; - - /* If string ends with G_SLASH, remove it. Don't do it if has length > 1, it - means that the string is just '/'. Note: our crappy version of Clang doesn't - seem to support std::string::back() */ - -#ifdef __APPLE__ - if (out[out.length() - 1] == G_SLASH && out.length() > 1) -#else - if (out.back() == G_SLASH && out.length() > 1) -#endif - - out = out.substr(0, out.size()-1); - return out; -} diff --git a/src/gui/elems/ge_browser.h b/src/gui/elems/ge_browser.h deleted file mode 100644 index e338143..0000000 --- a/src/gui/elems/ge_browser.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_browser - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_BROWSER_H -#define GE_BROWSER_H - -#include -#include -#include -#include "ge_mixed.h" - - -using std::string; - - -class gBrowser : public Fl_File_Browser -{ -private: - - string currentDir; - - /* normalize - * Make sure the string never ends with a trailing slash. */ - - string normalize(const string &s); - -public: - - gBrowser(int x, int y, int w, int h); - - /* init - * Initialize browser and show 'dir' as initial directory. */ - - void loadDir(const string &dir); - - /* getSelectedItem - * Return the full path or just the displayed name of the i-th selected item. - * Always with the trailing slash! */ - - string getSelectedItem(bool fullPath=true); - - string getCurrentDir(); - - void preselect(int position, int line); - - int handle(int e); -}; - -#endif diff --git a/src/gui/elems/ge_column.cpp b/src/gui/elems/ge_column.cpp deleted file mode 100644 index 7f8a046..0000000 --- a/src/gui/elems/ge_column.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_column - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/mixer.h" -#include "../../core/conf.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/channel.h" -#include "../../core/sampleChannel.h" -#include "../../core/midiChannel.h" -#include "../../glue/main.h" -#include "../../glue/channel.h" -#include "../../utils/log.h" -#include "../../utils/string.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_warnings.h" -#include "../elems/ge_keyboard.h" -#include "ge_column.h" -#include "channel.h" -#include "sampleChannel.h" -#include "midiChannel.h" - - -extern Mixer G_Mixer; -extern Conf G_Conf; -extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *mainWin; - - -gColumn::gColumn(int X, int Y, int W, int H, int index, gKeyboard *parent) - : Fl_Group(X, Y, W, H), parent(parent), index(index) -{ - /* gColumn does a bit of a mess: we pass a pointer to its parent (gKeyboard) and - the gColumn itself deals with the creation of another widget, outside gColumn - and inside gKeyboard, which handles the vertical resize bar (gResizerBar). - The resizer cannot stay inside gColumn: it needs a broader view on the other - side widgets. The view can be obtained from gKeyboard only (the upper level). - Unfortunately, parent() can be NULL: at this point (i.e the constructor) - gColumn is still detached from any parent. We use a custom gKeyboard *parent - instead. */ - - begin(); - addChannelBtn = new gClick(x(), y(), w(), 20, "Add new channel"); - end(); - - resizer = new gResizerBar(x()+w(), y(), 16, h(), false); - resizer->setMinSize(MIN_COLUMN_WIDTH); - parent->add(resizer); - - addChannelBtn->callback(cb_addChannel, (void*)this); -} - - -/* -------------------------------------------------------------------------- */ - - -gColumn::~gColumn() -{ - /* FIXME - this could actually cause a memory leak. resizer is - just removed, not deleted. But we cannot delete it right now. */ - - parent->remove(resizer); -} - - -/* -------------------------------------------------------------------------- */ - - - -int gColumn::handle(int e) -{ - switch (e) { - case FL_RELEASE: { - if (Fl::event_button() == FL_RIGHT_MOUSE) { - __cb_addChannel(); - return 1; - } - } - case FL_DND_ENTER: // return(1) for these events to 'accept' dnd - case FL_DND_DRAG: - case FL_DND_RELEASE: { - return 1; - } - case FL_PASTE: { // handle actual drop (paste) operation - vector paths; - gu_split(Fl::event_text(), "\n", &paths); - bool fails = false; - int result = 0; - for (unsigned i=0; iguiChannel); - fails = true; - } - } - if (fails) { - if (paths.size() > 1) - gdAlert("Some files were not loaded successfully."); - else - parent->printChannelMessage(result); - } - return 1; - } - } - - /* we return fl_Group::handle only if none of the cases above are fired. That - is because we don't want to propagate a dnd drop to all the sub widgets. */ - - return Fl_Group::handle(e); -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::resize(int X, int Y, int W, int H) -{ - /* resize all children */ - - int ch = children(); - for (int i=0; iresize(X, Y + (i * (c->h() + 4)), W, c->h()); - } - - /* resize group itself */ - - x(X); y(Y); w(W); h(H); - - /* resize resizerBar */ - - resizer->size(16, H); -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::refreshChannels() -{ - for (int i=1; irefresh(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::draw() -{ - fl_color(fl_rgb_color(27, 27, 27)); - fl_rectf(x(), y(), w(), h()); - - /* call draw and then redraw in order to avoid channel corruption when - scrolling horizontally */ - - for (int i=0; idraw(); - child(i)->redraw(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChannel(); } - - -/* -------------------------------------------------------------------------- */ - - -geChannel *gColumn::addChannel(Channel *ch) -{ - int currentY = y() + children() * 24; - geChannel *gch = NULL; - if (ch->type == CHANNEL_SAMPLE) - gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); - else - gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); - - add(gch); - resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop - gch->redraw(); // avoid corruption - parent->redraw(); // redraw Keyboard - return gch; -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::deleteChannel(geChannel *gch) -{ - gch->hide(); - remove(gch); - delete gch; - - /* reposition all other channels and resize this group */ - /** TODO - * reposition is useless when called by gColumn::clear(). Add a new - * parameter to skip the operation */ - - for (int i=0; iposition(gch->x(), y()+(i*24)); - } - size(w(), children() * 24 + 66); // evil space for drag n drop - redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::__cb_addChannel() -{ - gu_log("[gColumn::__cb_addChannel] index = %d\n", index); - int type = openTypeMenu(); - if (type) - glue_addChannel(index, type); -} - - -/* -------------------------------------------------------------------------- */ - - -int gColumn::openTypeMenu() -{ - Fl_Menu_Item rclick_menu[] = { - {"Sample channel"}, - {"MIDI channel"}, - {0} - }; - - Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); - b->textsize(GUI_FONT_SIZE_BASE); - b->textcolor(COLOR_TEXT_0); - b->color(COLOR_BG_0); - - const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); - if (!m) return 0; - - if (strcmp(m->label(), "Sample channel") == 0) - return CHANNEL_SAMPLE; - if (strcmp(m->label(), "MIDI channel") == 0) - return CHANNEL_MIDI; - return 0; -} - - -/* -------------------------------------------------------------------------- */ - - -void gColumn::clear(bool full) -{ - if (full) - Fl_Group::clear(); - else { - while (children() >= 2) { // skip "add new channel" btn - int i = children()-1; - deleteChannel((geChannel*)child(i)); - } - } -} - - -/* -------------------------------------------------------------------------- */ - - -Channel *gColumn::getChannel(int i) -{ - geChannel *gch = (geChannel*) child(i); - if (gch->type == CHANNEL_SAMPLE) - return ((geSampleChannel*) child(i))->ch; - else - return ((geMidiChannel*) child(i))->ch; -} diff --git a/src/gui/elems/ge_column.h b/src/gui/elems/ge_column.h deleted file mode 100644 index bcaa2ca..0000000 --- a/src/gui/elems/ge_column.h +++ /dev/null @@ -1,103 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_column - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_COLUMN_H -#define GE_COLUMN_H - - -#include -#include - - -class gColumn : public Fl_Group -{ -private: - - static void cb_addChannel (Fl_Widget *v, void *p); - inline void __cb_addChannel(); - - int openTypeMenu(); - - class gClick *addChannelBtn; - class gResizerBar *resizer; - class gKeyboard *parent; - - int index; - -public: - - gColumn(int x, int y, int w, int h, int index, class gKeyboard *parent); - ~gColumn(); - - /* addChannel - * add a new channel in this column and set the internal pointer - * to channel to 'ch'. */ - - class geChannel *addChannel(class Channel *ch); - - /* handle */ - - int handle(int e); - - /* resize - * custom resize behavior. */ - - void resize(int x, int y, int w, int h); - - /* deleteChannel - * remove the channel 'gch' from this column. */ - - void deleteChannel(geChannel *gch); - - /* refreshChannels - * update 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(); } -}; - - -#endif diff --git a/src/gui/elems/ge_controller.cpp b/src/gui/elems/ge_controller.cpp deleted file mode 100644 index 9ff5f25..0000000 --- a/src/gui/elems/ge_controller.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * ge_controller - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/graphics.h" -#include "../../glue/main.h" -#include "../../glue/io.h" -#include "ge_mixed.h" -#include "ge_controller.h" - - -gController::gController(int x, int y) - : Fl_Group(x, y, 131, 25) -{ - begin(); - - rewind = new gClick(x, y, 25, 25, "", rewindOff_xpm, rewindOn_xpm); - play = new gClick(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm); - recAction = new gClick(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm); - recInput = new gClick(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm); - metronome = new gClick(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm); - - end(); - - resizable(NULL); // don't resize any widget - - rewind->callback(cb_rewind, (void*)this); - - play->callback(cb_play); - play->type(FL_TOGGLE_BUTTON); - - recAction->callback(cb_recAction, (void*)this); - recAction->type(FL_TOGGLE_BUTTON); - - recInput->callback(cb_recInput, (void*)this); - recInput->type(FL_TOGGLE_BUTTON); - - metronome->callback(cb_metronome); - metronome->type(FL_TOGGLE_BUTTON); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::cb_rewind (Fl_Widget *v, void *p) { ((gController*)p)->__cb_rewind(); } -void gController::cb_play (Fl_Widget *v, void *p) { ((gController*)p)->__cb_play(); } -void gController::cb_recAction(Fl_Widget *v, void *p) { ((gController*)p)->__cb_recAction(); } -void gController::cb_recInput (Fl_Widget *v, void *p) { ((gController*)p)->__cb_recInput(); } -void gController::cb_metronome(Fl_Widget *v, void *p) { ((gController*)p)->__cb_metronome(); } - - -/* -------------------------------------------------------------------------- */ - - -void gController::__cb_rewind() -{ - glue_rewindSeq(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::__cb_play() -{ - glue_startStopSeq(true); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::__cb_recAction() -{ - glue_startStopActionRec(true); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::__cb_recInput() -{ - glue_startStopInputRec(true); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::__cb_metronome() -{ - glue_startStopMetronome(true); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::updatePlay(int v) -{ - play->value(v); - play->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::updateMetronome(int v) -{ - metronome->value(v); - metronome->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::updateRecInput(int v) -{ - recInput->value(v); - recInput->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gController::updateRecAction(int v) -{ - recAction->value(v); - recAction->redraw(); -} diff --git a/src/gui/elems/ge_controller.h b/src/gui/elems/ge_controller.h deleted file mode 100644 index 4c4aa6c..0000000 --- a/src/gui/elems/ge_controller.h +++ /dev/null @@ -1,68 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * ge_controller - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_CONTROLLER_H -#define GE_CONTROLLER_H - - -#include - - -class gController : public Fl_Group -{ -private: - - class gClick *rewind; - class gClick *play; - class gClick *recAction; - class gClick *recInput; - class gClick *metronome; - - static void cb_rewind (Fl_Widget *v, void *p); - static void cb_play (Fl_Widget *v, void *p); - static void cb_recAction(Fl_Widget *v, void *p); - static void cb_recInput (Fl_Widget *v, void *p); - static void cb_metronome(Fl_Widget *v, void *p); - - inline void __cb_rewind (); - inline void __cb_play (); - inline void __cb_recAction(); - inline void __cb_recInput (); - inline void __cb_metronome(); - -public: - - gController(int x, int y); - - void updatePlay (int v); - void updateMetronome(int v); - void updateRecInput (int v); - void updateRecAction(int v); -}; - -#endif diff --git a/src/gui/elems/ge_keyboard.cpp b/src/gui/elems/ge_keyboard.cpp deleted file mode 100644 index 68a8228..0000000 --- a/src/gui/elems/ge_keyboard.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gg_keyboard - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/mixer.h" -#include "../../core/conf.h" -#include "../../core/const.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/channel.h" -#include "../../core/sampleChannel.h" -#include "../../glue/main.h" -#include "../../glue/io.h" -#include "../../utils/log.h" -#include "../dialogs/gd_browser.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_editor.h" -#include "../dialogs/gd_warnings.h" -#include "channel.h" -#include "sampleChannel.h" -#include "ge_keyboard.h" - - -extern Mixer G_Mixer; -extern Conf G_Conf; -extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *mainWin; - - -int gKeyboard::indexColumn = 0; - - -/* -------------------------------------------------------------------------- */ - - -gKeyboard::gKeyboard(int X, int Y, int W, int H) -: Fl_Scroll (X, Y, W, H), - bckspcPressed(false), - endPressed (false), - spacePressed (false), - addColumnBtn (NULL) -{ - color(COLOR_BG_MAIN); - type(Fl_Scroll::BOTH_ALWAYS); - scrollbar.color(COLOR_BG_0); - scrollbar.selection_color(COLOR_BG_1); - scrollbar.labelcolor(COLOR_BD_1); - scrollbar.slider(G_BOX); - hscrollbar.color(COLOR_BG_0); - hscrollbar.selection_color(COLOR_BG_1); - hscrollbar.labelcolor(COLOR_BD_1); - hscrollbar.slider(G_BOX); - - addColumnBtn = new gClick(8, y(), 200, 20, "Add new column"); - addColumnBtn->callback(cb_addColumn, (void*) this); - add(addColumnBtn); - - init(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::init() -{ - /* add 6 empty columns as init layout */ - - __cb_addColumn(); - __cb_addColumn(); - __cb_addColumn(); - __cb_addColumn(); - __cb_addColumn(); - __cb_addColumn(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::freeChannel(geChannel *gch) -{ - gch->reset(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::deleteChannel(geChannel *gch) -{ - for (unsigned i=0; ifind(gch); - if (k != columns.at(i)->children()) { - columns.at(i)->deleteChannel(gch); - return; - } - } -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::updateChannel(geChannel *gch) -{ - gch->update(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::organizeColumns() -{ - /* if only one column exists don't cleanup: the initial column must - * stay here. */ - - if (columns.size() == 1) - return; - - /* otherwise delete all empty columns */ - /** FIXME - this for loop might not work correctly! */ - - for (unsigned i=columns.size()-1; i>=1; i--) { - if (columns.at(i)->isEmpty()) { - //Fl::delete_widget(columns.at(i)); - delete columns.at(i); - columns.erase(columns.begin() + i); - } - } - - /* compact column, avoid empty spaces */ - - for (unsigned i=1; iposition(columns.at(i-1)->x() + columns.at(i-1)->w() + 16, y()); - - addColumnBtn->position(columns.back()->x() + columns.back()->w() + 16, y()); - - /* recompute col indexes */ - - refreshColIndexes(); - - redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) -{ - ((gKeyboard*)p)->__cb_addColumn(DEFAULT_COLUMN_WIDTH); -} - - -/* -------------------------------------------------------------------------- */ - - -geChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) -{ - gColumn *col = getColumnByIndex(colIndex); - - /* no column with index 'colIndex' found? Just create it and set its index - to 'colIndex'. */ - - if (!col) { - __cb_addColumn(); - col = columns.back(); - col->setIndex(colIndex); - gu_log("[gKeyboard::addChannel] created new column with index=%d\n", colIndex); - } - - gu_log("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex()); - return col->addChannel(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::refreshColumns() -{ - for (unsigned i=0; irefreshChannels(); -} - - -/* -------------------------------------------------------------------------- */ - - -gColumn *gKeyboard::getColumnByIndex(int index) -{ - for (unsigned i=0; igetIndex() == index) - return columns.at(i); - return NULL; -} - - -/* -------------------------------------------------------------------------- */ - -/* TODO - the following event handling for play, stop, rewind, start rec and -so on should be moved to the proper widget: gdMainWindow or (better) geController. */ - -int gKeyboard::handle(int e) -{ - int ret = Fl_Group::handle(e); // assume the buttons won't handle the Keyboard events - switch (e) { - case FL_FOCUS: - case FL_UNFOCUS: { - ret = 1; // enables receiving Keyboard events - break; - } - case FL_SHORTCUT: // in case widget that isn't ours has focus - case FL_KEYDOWN: // Keyboard key pushed - case FL_KEYUP: { // Keyboard key released - - /* rewind session. Avoid retrigs */ - - if (e == FL_KEYDOWN) { - if (Fl::event_key() == FL_BackSpace && !bckspcPressed) { - bckspcPressed = true; - glue_rewindSeq(); - ret = 1; - break; - } - else if (Fl::event_key() == FL_End && !endPressed) { - endPressed = true; - glue_startStopInputRec(false); // update gui - ret = 1; - break; - } - else if (Fl::event_key() == FL_Enter && !enterPressed) { - enterPressed = true; - glue_startStopActionRec(false); // update gui - ret = 1; - break; - } - else if (Fl::event_key() == ' ' && !spacePressed) { - spacePressed = true; - glue_startStopSeq(false); // update gui - ret = 1; - break; - } - } - else if (e == FL_KEYUP) { - if (Fl::event_key() == FL_BackSpace) - bckspcPressed = false; - else if (Fl::event_key() == FL_End) - endPressed = false; - else if (Fl::event_key() == ' ') - spacePressed = false; - else if (Fl::event_key() == FL_Enter) - enterPressed = false; - } - - /* Walk button arrays, trying to match button's label with the Keyboard event. - * If found, set that button's value() based on up/down event, - * and invoke that button's callback() */ - - for (unsigned i=0; ichildren(); k++) - ret &= ((geChannel*)columns.at(i)->child(k))->keyPress(e); - break; - } - } - return ret; -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::clear() -{ - for (unsigned i=0; iposition(8, y()); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::setChannelWithActions(geSampleChannel *gch) -{ - if (gch->ch->hasActions) - gch->showActionButton(); - else - gch->hideActionButton(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::printChannelMessage(int res) -{ - if (res == SAMPLE_NOT_VALID) - gdAlert("This is not a valid WAVE file."); - else if (res == SAMPLE_MULTICHANNEL) - gdAlert("Multichannel samples not supported."); - else if (res == SAMPLE_WRONG_BIT) - gdAlert("This sample has an\nunsupported bit-depth (> 32 bit)."); - else if (res == SAMPLE_WRONG_ENDIAN) - gdAlert("This sample has a wrong\nbyte order (not little-endian)."); - else if (res == SAMPLE_WRONG_FORMAT) - gdAlert("This sample is encoded in\nan unsupported audio format."); - else if (res == SAMPLE_READ_ERROR) - gdAlert("Unable to read this sample."); - else if (res == SAMPLE_PATH_TOO_LONG) - gdAlert("File path too long."); - else - gdAlert("Unknown error."); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::__cb_addColumn(int width) -{ - int colx; - int colxw; - int gap = 16; - if (columns.size() == 0) { - colx = x() - xposition(); // mind the offset with xposition() - colxw = colx + width; - } - else { - gColumn *prev = columns.back(); - colx = prev->x()+prev->w() + gap; - colxw = colx + width; - } - - /* add gColumn to gKeyboard and to columns vector */ - - gColumn *gc = new gColumn(colx, y(), width, 2000, indexColumn, this); - add(gc); - columns.push_back(gc); - indexColumn++; - - /* move addColumn button */ - - addColumnBtn->position(colxw + gap, y()); - redraw(); - - gu_log("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", - gc->getIndex(), width, columns.size(), addColumnBtn->x()); - - /* recompute col indexes */ - - refreshColIndexes(); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::addColumn(int width) -{ - __cb_addColumn(width); -} - - -/* -------------------------------------------------------------------------- */ - - -void gKeyboard::refreshColIndexes() -{ - for (unsigned i=0; isetIndex(i); -} diff --git a/src/gui/elems/ge_keyboard.h b/src/gui/elems/ge_keyboard.h deleted file mode 100644 index c5558b9..0000000 --- a/src/gui/elems/ge_keyboard.h +++ /dev/null @@ -1,167 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gg_keyboard - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_KEYBOARD_H -#define GE_KEYBOARD_H - - -#include -#include -#include -#include -#include -#include -#include "../elems/ge_column.h" -#include "../../core/const.h" -#include "../../utils/fs.h" - - -using std::vector; - - -class gKeyboard : public Fl_Scroll -{ -private: - - /* refreshColIndexes - * Recompute all column indexes in order to avoid any gaps between them. - * Indexes must always be contiguous! */ - - void refreshColIndexes(); - - static void cb_addColumn (Fl_Widget *v, void *p); - inline void __cb_addColumn(int width=DEFAULT_COLUMN_WIDTH); - - bool bckspcPressed; - bool endPressed; - bool spacePressed; - bool enterPressed; - - /* indexColumn - * the last index used for column. */ - - static int indexColumn; - - class gClick *addColumnBtn; - - /* columns - * a vector of columns which in turn contain channels. */ - - vector columns; - -public: - - gKeyboard(int X, int Y, int W, int H); - - int handle(int e); - - /* init - * build the initial setup of empty channels. */ - - 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. */ - - class geChannel *addChannel(int column, class Channel *ch, bool build=false); - - /* addColumn - * add a new column to the top of the stack. */ - - void addColumn(int width=380); - - /* deleteChannel - * delete a channel from geChannels<> where geChannel->ch == ch and remove - * it from the stack. */ - - void deleteChannel(geChannel *gch); - - /* freeChannel - * free a channel from geChannels<> where geChannel->ch == ch. No channels - * are deleted */ - - void freeChannel(geChannel *gch); - - /* updateChannel - * wrapper function to call gch->update(). */ - - void updateChannel(geChannel *gch); - - /* organizeColumns - * reorganize columns layout by removing empty gaps. */ - - void organizeColumns(); - - /* refreshColumns - * refresh each column's channel, called on each GUI cycle. */ - - void refreshColumns(); - - /* getColumnByIndex - * return the column with index 'index', or NULL if not found. */ - - gColumn *getColumnByIndex(int index); - - /* getColumn - * return the column with from columns->at(i). */ - - inline gColumn *getColumn(int i) { return columns.at(i); } - - /* clear - * delete all channels and groups. */ - - void clear(); - - /* setChannelWithActions - * add 'R' button if channel has actions, and set recorder to active. */ - - void setChannelWithActions(class geSampleChannel *gch); - - /* printChannelMessage - * given any output by glue_loadChannel, print the message on screen - * on a gdAlert subwindow. */ - - void printChannelMessage(int res); - - /* getTotalColumns */ - - inline unsigned getTotalColumns() { return columns.size(); } - - /* getColumnWidth - * return the width in pixel of i-th column. Warning: 'i' is the i-th column - * in the column array, NOT the index. */ - - inline int getColumnWidth(int i) { return getColumnByIndex(i)->w(); } -}; - - -#endif diff --git a/src/gui/elems/ge_midiIoTools.cpp b/src/gui/elems/ge_midiIoTools.cpp deleted file mode 100644 index 8c20101..0000000 --- a/src/gui/elems/ge_midiIoTools.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_midiIoTools - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "ge_mixed.h" -#include "ge_midiIoTools.h" - - -extern KernelMidi G_KernelMidi; - - -gLearner::gLearner(int X, int Y, int W, const char *l, KernelMidi::cb_midiLearn *cb, - uint32_t *param) - : Fl_Group(X, Y, W, 20), - callback(cb), - param (param) -{ - begin(); - text = new gBox(x(), y(), 156, 20, l); - value = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)"); - button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn"); - end(); - - text->box(G_BOX); - text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); - - value->box(G_BOX); - value->callback(cb_value, (void*)this); - value->when(FL_WHEN_RELEASE); - updateValue(); - - button->type(FL_TOGGLE_BUTTON); - button->callback(cb_button, (void*)this); -} - - -/* -------------------------------------------------------------------------- */ - - -void gLearner::updateValue() { - char buf[16]; - if (*param != 0x0) - snprintf(buf, 9, "0x%X", *param); - else - snprintf(buf, 16, "(not set)"); - value->copy_label(buf); - button->value(0); -} - - -/* -------------------------------------------------------------------------- */ - - -void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); } -void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); } - - -/* -------------------------------------------------------------------------- */ - - -void gLearner::__cb_value() { - if (Fl::event_button() == FL_RIGHT_MOUSE) { - *param = 0x0; - updateValue(); - } - /// TODO - elif (LEFT_MOUSE) : insert values by hand -} - - -/* -------------------------------------------------------------------------- */ - - -/* FIXME - do not malloc on each callback! do it on the constructor! */ - -void gLearner::__cb_button() { - if (button->value() == 1) { - cbData *data = (cbData*) malloc(sizeof(cbData)); - data->window = (gdMidiInput*) parent(); // parent = gdMidiGrabberChannel - data->learner = this; - G_KernelMidi.startMidiLearn(callback, (void*)data); - } - else - G_KernelMidi.stopMidiLearn(); -} diff --git a/src/gui/elems/ge_midiIoTools.h b/src/gui/elems/ge_midiIoTools.h deleted file mode 100644 index 0712937..0000000 --- a/src/gui/elems/ge_midiIoTools.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_midiIoTools - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_LEARNER_H -#define GE_LEARNER_H - - -#include -#include "../../core/kernelMidi.h" -#include "../dialogs/gd_midiInput.h" - - -extern KernelMidi G_KernelMidi; - - -class gLearner : public Fl_Group -{ -private: - - /* callback - * cb to pass to kernelMidi. Requires two parameters: - * uint32_t msg - MIDI message - * void *data - extra data */ - - KernelMidi::cb_midiLearn *callback; - - class gBox *text; - class gClick *value; - class gButton *button; - - static void cb_button(Fl_Widget *v, void *p); - static void cb_value (Fl_Widget *v, void *p); - inline void __cb_button(); - inline void __cb_value(); - -public: - - /* param - * pointer to ch->midiIn[value] */ - - uint32_t *param; - - gLearner(int x, int y, int w, const char *l, KernelMidi::cb_midiLearn *cb, uint32_t *param); - - void updateValue(); -}; - - -/* -------------------------------------------------------------------------- */ - - -/* cbData - * struct we pass to kernelMidi as extra parameter. Local scope made - * with unnamed namespace. Infos: - * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */ - -/* TODO - instead of the unnamed namespace, why don't we make the struct as a -(static) member of gLearner? */ - -namespace { - struct cbData { - gdMidiInput *window; - gLearner *learner; - }; -} - - -#endif diff --git a/src/gui/elems/ge_mixed.cpp b/src/gui/elems/ge_mixed.cpp index 0969a8a..913f023 100644 --- a/src/gui/elems/ge_mixed.cpp +++ b/src/gui/elems/ge_mixed.cpp @@ -36,6 +36,7 @@ #include "../../core/sampleChannel.h" #include "../../utils/gui.h" #include "../dialogs/gd_mainWindow.h" +#include "basics/boxtypes.h" #include "ge_mixed.h" @@ -130,8 +131,8 @@ void gClickRepeat::draw() gInput::gInput(int x, int y, int w, int h, const char *L) : Fl_Input(x, y, w, h, L) { - //Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2); - box(G_BOX); + //Fl::set_boxtype(G_CUSTOM_BORDER_BOX, gDrawBox, 1, 1, 2, 2); + box(G_CUSTOM_BORDER_BOX); labelsize(GUI_FONT_SIZE_BASE); labelcolor(COLOR_TEXT_0); color(COLOR_BG_DARK); @@ -173,8 +174,9 @@ void gDial::draw() gBox::gBox(int x, int y, int w, int h, const char *L, Fl_Align al) -: Fl_Box(x, y, w, h, L) +: Fl_Box(x, y, w, h) { + copy_label(L); labelsize(GUI_FONT_SIZE_BASE); box(FL_NO_BOX); labelcolor(COLOR_TEXT_0); @@ -241,7 +243,7 @@ void gRadio::draw() gProgress::gProgress(int x, int y, int w, int h, const char *L) : Fl_Progress(x, y, w, h, L) { color(COLOR_BG_0, COLOR_BD_0); - box(G_BOX); + box(G_CUSTOM_BORDER_BOX); } @@ -294,38 +296,6 @@ void gSoundMeter::draw() fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !G_audio_status ? COLOR_ALERT : COLOR_BD_0); } -/* -------------------------------------------------------------------------- */ - -gBeatMeter::gBeatMeter(int x, int y, int w, int h, const char *L) - : Fl_Box(x, y, w, h, L) {} - -void gBeatMeter::draw() -{ - int cursorW = w() / MAX_BEATS; - int greyX = G_Mixer.beats * cursorW; - - fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border - fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR); // bg - fl_rectf(x()+(G_Mixer.actualBeat*cursorW)+3, y()+3, cursorW-5, h()-6, COLOR_BG_2); // cursor - - /* beat cells */ - - fl_color(COLOR_BD_0); - for (int i=1; i<=G_Mixer.beats; i++) - fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2); - - /* bar line */ - - fl_color(COLOR_BG_2); - int delta = G_Mixer.beats / G_Mixer.bars; - for (int i=1; i. - * - * -------------------------------------------------------------------------- */ - - -#include "../../utils/gui.h" -#include "../../core/graphics.h" -#include "../../core/sampleChannel.h" -#include "../../core/const.h" -#include "../dialogs/gd_mainWindow.h" -#include "ge_modeBox.h" - - -gModeBox::gModeBox(int x, int y, int w, int h, SampleChannel *ch, const char *L) - : Fl_Menu_Button(x, y, w, h, L), ch(ch) -{ - box(G_BOX); - textsize(GUI_FONT_SIZE_BASE); - textcolor(COLOR_TEXT_0); - color(COLOR_BG_0); - - add("Loop . basic", 0, cb_changeMode, (void *)LOOP_BASIC); - add("Loop . once", 0, cb_changeMode, (void *)LOOP_ONCE); - add("Loop . once . bar", 0, cb_changeMode, (void *)LOOP_ONCE_BAR); - add("Loop . repeat", 0, cb_changeMode, (void *)LOOP_REPEAT); - add("Oneshot . basic", 0, cb_changeMode, (void *)SINGLE_BASIC); - add("Oneshot . press", 0, cb_changeMode, (void *)SINGLE_PRESS); - add("Oneshot . retrig", 0, cb_changeMode, (void *)SINGLE_RETRIG); - add("Oneshot . endless", 0, cb_changeMode, (void *)SINGLE_ENDLESS); -} - - -/* -------------------------------------------------------------------------- */ - - -void gModeBox::draw() { - fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border - switch (ch->mode) { - case LOOP_BASIC: - fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1); - break; - case LOOP_ONCE: - fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1); - break; - case LOOP_ONCE_BAR: - fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1); - break; - case LOOP_REPEAT: - fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1); - break; - case SINGLE_BASIC: - fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1); - break; - case SINGLE_PRESS: - fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1); - break; - case SINGLE_RETRIG: - fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1); - break; - case SINGLE_ENDLESS: - fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1); - break; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void gModeBox::cb_changeMode(Fl_Widget *v, void *p) { ((gModeBox*)v)->__cb_changeMode((intptr_t)p); } - - -/* -------------------------------------------------------------------------- */ - - -void gModeBox::__cb_changeMode(int mode) -{ - ch->mode = mode; - - /* what to do when the channel is playing and you change the mode? - * Nothing, since v0.5.3. Just refresh the action editor window, in - * case it's open */ - - gu_refreshActionEditor(); -} diff --git a/src/gui/elems/ge_modeBox.h b/src/gui/elems/ge_modeBox.h deleted file mode 100644 index 2e82cd3..0000000 --- a/src/gui/elems/ge_modeBox.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_modeBox - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_MODEBOX_H -#define GE_MODEBOX_H - - -#include - - -class gModeBox : public Fl_Menu_Button -{ -private: - - static void cb_changeMode (Fl_Widget *v, void *p); - inline void __cb_changeMode(int mode); - - class SampleChannel *ch; - -public: - - gModeBox(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0); - void draw(); -}; - - -#endif diff --git a/src/gui/elems/ge_pluginBrowser.cpp b/src/gui/elems/ge_pluginBrowser.cpp index 21baf73..2754fea 100644 --- a/src/gui/elems/ge_pluginBrowser.cpp +++ b/src/gui/elems/ge_pluginBrowser.cpp @@ -34,6 +34,7 @@ #include "../../core/const.h" #include "../../core/pluginHost.h" #include "ge_mixed.h" +#include "basics/boxtypes.h" #include "ge_pluginBrowser.h" @@ -46,7 +47,7 @@ using std::vector; gePluginBrowser::gePluginBrowser(int x, int y, int w, int h) : Fl_Browser(x, y, w, h) { - box(G_BOX); + box(G_CUSTOM_BORDER_BOX); textsize(GUI_FONT_SIZE_BASE); textcolor(COLOR_TEXT_0); selection_color(COLOR_BG_1); @@ -55,12 +56,12 @@ gePluginBrowser::gePluginBrowser(int x, int y, int w, int h) this->scrollbar.color(COLOR_BG_0); this->scrollbar.selection_color(COLOR_BG_1); this->scrollbar.labelcolor(COLOR_BD_1); - this->scrollbar.slider(G_BOX); + this->scrollbar.slider(G_CUSTOM_BORDER_BOX); this->hscrollbar.color(COLOR_BG_0); this->hscrollbar.selection_color(COLOR_BG_1); this->hscrollbar.labelcolor(COLOR_BD_1); - this->hscrollbar.slider(G_BOX); + this->hscrollbar.slider(G_CUSTOM_BORDER_BOX); type(FL_HOLD_BROWSER); @@ -81,7 +82,7 @@ gePluginBrowser::gePluginBrowser(int x, int y, int w, int h) void gePluginBrowser::refresh() { clear(); - + add("NAME\tMANUFACTURER\tCATEGORY\tFORMAT\tUID"); add("---\t---\t---\t---\t---"); diff --git a/src/gui/elems/ge_status.cpp b/src/gui/elems/ge_status.cpp deleted file mode 100644 index 80cbac7..0000000 --- a/src/gui/elems/ge_status.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_status - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/mixer.h" -#include "../../core/const.h" -#include "ge_status.h" - - -extern Mixer G_Mixer; -extern Recorder G_Recorder; - - -gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L) - : Fl_Box(x, y, w, h, L), ch(ch) {} - - -/* -------------------------------------------------------------------------- */ - - -void gStatus::draw() -{ - fl_rect(x(), y(), w(), h(), COLOR_BD_0); // reset border - fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // reset background - - if (ch != NULL) { - if (ch->status & (STATUS_WAIT | STATUS_ENDING | REC_ENDING | REC_WAITING) || - ch->recStatus & (REC_WAITING | REC_ENDING)) - { - fl_rect(x(), y(), w(), h(), COLOR_BD_1); - } - else - if (ch->status == STATUS_PLAY) - fl_rect(x(), y(), w(), h(), COLOR_BD_1); - else - fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // status empty - - - if (G_Mixer.recording && ch->armed) - fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3); // take in progress - else - if (G_Recorder.active && G_Recorder.canRec(ch)) - fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4); // action record - - /* equation for the progress bar: - * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */ - - int pos = ch->getPosition(); - if (pos == -1) - pos = 0; - else - pos = (pos * (w()-1)) / (ch->end - ch->begin); - fl_rectf(x()+1, y()+1, pos, h()-2, COLOR_BG_2); - } -} diff --git a/src/gui/elems/ge_status.h b/src/gui/elems/ge_status.h deleted file mode 100644 index e75d919..0000000 --- a/src/gui/elems/ge_status.h +++ /dev/null @@ -1,48 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_status - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_STATUS_H -#define GE_STATUS_H - - -#include -#include "../../core/sampleChannel.h" -#include "ge_mixed.h" - - -class gStatus : public Fl_Box -{ -public: - gStatus(int X, int Y, int W, int H, class SampleChannel *ch, const char *L=0); - void draw(); - class SampleChannel *ch; -}; - - -#endif diff --git a/src/gui/elems/ge_waveTools.cpp b/src/gui/elems/ge_waveTools.cpp index 7e7b197..e2ec4b7 100644 --- a/src/gui/elems/ge_waveTools.cpp +++ b/src/gui/elems/ge_waveTools.cpp @@ -32,6 +32,7 @@ #include "../../core/const.h" #include "../elems/ge_mixed.h" #include "../elems/ge_waveform.h" +#include "basics/boxtypes.h" #include "ge_waveTools.h" @@ -42,7 +43,7 @@ gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char hscrollbar.color(COLOR_BG_0); hscrollbar.selection_color(COLOR_BG_1); hscrollbar.labelcolor(COLOR_BD_1); - hscrollbar.slider(G_BOX); + hscrollbar.slider(G_CUSTOM_BORDER_BOX); waveform = new gWaveform(x, y, w, h-24, ch); diff --git a/src/gui/elems/ge_waveform.cpp b/src/gui/elems/ge_waveform.cpp index dd893ce..022257f 100644 --- a/src/gui/elems/ge_waveform.cpp +++ b/src/gui/elems/ge_waveform.cpp @@ -42,6 +42,7 @@ #include "../dialogs/gd_editor.h" #include "ge_waveTools.h" #include "ge_mixed.h" +#include "basics/boxtypes.h" #include "ge_waveform.h" @@ -621,7 +622,7 @@ void gWaveform::openEditMenu() } Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); + b->box(G_CUSTOM_BORDER_BOX); b->textsize(GUI_FONT_SIZE_BASE); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); diff --git a/src/gui/elems/mainWindow/beatMeter.cpp b/src/gui/elems/mainWindow/beatMeter.cpp new file mode 100644 index 0000000..d0bb077 --- /dev/null +++ b/src/gui/elems/mainWindow/beatMeter.cpp @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * beatMeter + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../../../core/const.h" +#include "../../../core/mixer.h" +#include "beatMeter.h" + + +extern Mixer G_Mixer; + + +geBeatMeter::geBeatMeter(int x, int y, int w, int h, const char *L) + : Fl_Box(x, y, w, h, L) {} + + +/* -------------------------------------------------------------------------- */ + + +void geBeatMeter::draw() +{ + int cursorW = w() / MAX_BEATS; + int greyX = G_Mixer.beats * cursorW; + + fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border + fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR); // bg + fl_rectf(x()+(G_Mixer.actualBeat*cursorW)+3, y()+3, cursorW-5, h()-6, + COLOR_BG_2); // cursor + + /* beat cells */ + + fl_color(COLOR_BD_0); + for (int i=1; i<=G_Mixer.beats; i++) + fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2); + + /* bar line */ + + fl_color(COLOR_BG_2); + int delta = G_Mixer.beats / G_Mixer.bars; + for (int i=1; i. + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_BEAT_METER_H +#define GE_BEAT_METER_H + + +#include + + +class geBeatMeter : public Fl_Box +{ +public: + + geBeatMeter(int X,int Y,int W,int H,const char *L=0); + void draw(); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/channel.cpp b/src/gui/elems/mainWindow/keyboard/channel.cpp new file mode 100644 index 0000000..1114d7c --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channel.cpp @@ -0,0 +1,237 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_channel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/const.h" +#include "../../../../core/channel.h" +#include "../../../../core/graphics.h" +#include "../../../../core/pluginHost.h" +#include "../../../../utils/gui.h" +#include "../../../../glue/channel.h" +#include "../../../dialogs/gd_mainWindow.h" +#include "../../../dialogs/gd_pluginList.h" +#include "column.h" +#include "channelButton.h" +#include "channel.h" + + +extern gdMainWindow *G_MainWin; + + +geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch) + : Fl_Group(X, Y, W, H, NULL), + ch (ch), + type (type) +{ +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::cb_arm(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_arm(); } +void geChannel::cb_mute(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_mute(); } +void geChannel::cb_solo(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_solo(); } +void geChannel::cb_changeVol(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_changeVol(); } +#ifdef WITH_VST +void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_openFxWindow(); } +#endif + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_arm() +{ + glue_toggleArm(ch, true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_mute() +{ + glue_setMute(ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_solo() +{ + solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_changeVol() +{ + glue_setChanVol(ch, vol->value()); +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST +void geChannel::__cb_openFxWindow() +{ + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); +} +#endif + + +/* -------------------------------------------------------------------------- */ + + +int geChannel::keyPress(int e) +{ + return handleKey(e, ch->key); +} + + +/* -------------------------------------------------------------------------- */ + + + +int geChannel::getColumnIndex() +{ + return ((geColumn*)parent())->getIndex(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::blink() +{ + if (gu_getBlinker() > 6) + mainButton->setPlayMode(); + else + mainButton->setDefaultMode(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::setColorsByStatus(int playStatus, int recStatus) +{ + switch (playStatus) { + case STATUS_OFF: + case STATUS_EMPTY: + mainButton->setDefaultMode(); + button->imgOn = channelPlay_xpm; + button->imgOff = channelStop_xpm; + button->redraw(); + break; + case STATUS_PLAY: + mainButton->setPlayMode(); + button->imgOn = channelStop_xpm; + button->imgOff = channelPlay_xpm; + button->redraw(); + break; + case STATUS_WAIT: + blink(); + break; + case STATUS_ENDING: + mainButton->setEndingMode(); + break; + } + + switch (recStatus) { + case REC_WAITING: + blink(); + break; + case REC_ENDING: + mainButton->setEndingMode(); + break; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::packWidgets() +{ + /* Count visible widgets and resize mainButton according to how many widgets + are visible. */ + + int visibles = 0; + for (int i=0; isize(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; ivisible()) + continue; + for (int k=i-1; k>=0; k--) // Get the first visible item prior to i + if (child(k)->visible()) { + p = k; + break; + } + child(i)->position(child(p)->x() + child(p)->w() + 4, y()); + } + + init_sizes(); // Resets the internal array of widget sizes and positions +} + + +/* -------------------------------------------------------------------------- */ + + +int geChannel::handleKey(int e, int key) +{ + int ret; + if (e == FL_KEYDOWN && button->value()) // key already pressed! skip it + ret = 1; + else + if (Fl::event_key() == key && !button->value()) { + button->take_focus(); // move focus to this button + button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state + button->do_callback(); // invoke the button's callback + ret = 1; + } + else + ret = 0; + + if (Fl::event_key() == key) + button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state + + return ret; +} diff --git a/src/gui/elems/mainWindow/keyboard/channel.h b/src/gui/elems/mainWindow/keyboard/channel.h new file mode 100644 index 0000000..f76378f --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channel.h @@ -0,0 +1,139 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_channel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_CHANNEL_H +#define GE_CHANNEL_H + + +#include + + +class geChannel : public Fl_Group +{ +protected: + + /* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of + pixels to shrink sampleButton. */ + +#ifdef WITH_VST + static const int BREAK_READ_ACTIONS = 240; + static const int BREAK_MODE_BOX = 216; + static const int BREAK_FX = 192; + static const int BREAK_ARM = 168; +#else + static const int BREAK_READ_ACTIONS = 216; + static const int BREAK_MODE_BOX = 192; + static const int BREAK_ARM = 168; +#endif + + static void cb_arm (Fl_Widget *v, void *p); + static void cb_mute (Fl_Widget *v, void *p); + static void cb_solo (Fl_Widget *v, void *p); + static void cb_changeVol (Fl_Widget *v, void *p); +#ifdef WITH_VST + static void cb_openFxWindow(Fl_Widget *v, void *p); +#endif + + inline void __cb_mute(); + inline void __cb_arm(); + inline void __cb_solo(); + inline void __cb_changeVol(); +#ifdef WITH_VST + inline void __cb_openFxWindow(); +#endif + + /* blink + * blink button when channel is in wait/ending status. */ + + void blink(); + + /* setColorByStatus + * update colors depending on channel status. */ + + void setColorsByStatus(int playStatus, int recStatus); + + /* handleKey + * method wrapped by virtual handle(int e). */ + + int handleKey(int e, int key); + + /* packWidgets + Spread widgets across available space. */ + + void packWidgets(); + +public: + + geChannel(int x, int y, int w, int h, int type, class Channel *ch); + + /* reset + * reset channel to initial status. */ + + virtual void reset() = 0; + + /* update + * update the label of sample button and everything else such as 'R' + * button, key box and so on, according to global values. */ + + virtual void update() = 0; + + /* refresh + * update graphics. */ + + virtual void refresh() = 0; + + /* keypress + * what to do when the corresponding key is pressed. */ + + int keyPress(int event); + + /* getColumnIndex + * return the numeric index of the column in which this channel is + * located. */ + + int getColumnIndex(); + + class Channel *ch; + + class gButton *button; + class geChannelStatus *status; + class gClick *arm; + class geChannelButton *mainButton; + class gClick *mute; + class gClick *solo; + class gDial *vol; +#ifdef WITH_VST + class gFxButton *fx; +#endif + + int type; +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/channelButton.cpp b/src/gui/elems/mainWindow/keyboard/channelButton.cpp new file mode 100644 index 0000000..9a17eb4 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelButton.cpp @@ -0,0 +1,136 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_channelButton + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/const.h" +#include "channelButton.h" + + +using std::string; + + +geChannelButton::geChannelButton(int x, int y, int w, int h, const char *l) + : gClick(x, y, w, h, l), key("") {} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setKey(const string &k) +{ + key = k; +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setKey(int k) +{ + if (k == 0) + key = ""; + else { + // FIXME - this crap won't work with unicode/utf-8 + char c = (char) k; + key = c; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::draw() +{ + gClick::draw(); + + if (key == "") + return; + + /* draw background */ + + fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0); + + /* draw key */ + + fl_color(COLOR_TEXT_0); + fl_font(FL_HELVETICA, 11); + fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setInputRecordMode() +{ + bgColor0 = COLOR_BG_3; +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setActionRecordMode() +{ + bgColor0 = COLOR_BG_4; + txtColor = COLOR_TEXT_0; +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setDefaultMode(const char *l) +{ + bgColor0 = COLOR_BG_0; + bdColor = COLOR_BD_0; + txtColor = COLOR_TEXT_0; + if (l) + label(l); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setPlayMode() +{ + bgColor0 = COLOR_BG_2; + bdColor = COLOR_BD_1; + txtColor = COLOR_TEXT_1; +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelButton::setEndingMode() +{ + bgColor0 = COLOR_BD_0; +} diff --git a/src/gui/elems/mainWindow/keyboard/channelButton.h b/src/gui/elems/mainWindow/keyboard/channelButton.h new file mode 100644 index 0000000..5163983 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelButton.h @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_channelButton + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_CHANNEL_BUTTON_H +#define GE_CHANNEL_BUTTON_H + + +#include "../../ge_mixed.h" + + +class geChannelButton : public gClick +{ +private: + + std::string key; + +public: + + geChannelButton(int x, int y, int w, int h, const char *l=0); + + virtual int handle(int e) = 0; + + void draw(); + void setKey(const std::string &k); + void setKey(int k); + void setPlayMode(); + void setEndingMode(); + void setDefaultMode(const char *l=0); + void setInputRecordMode(); + void setActionRecordMode(); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/channelMode.cpp b/src/gui/elems/mainWindow/keyboard/channelMode.cpp new file mode 100644 index 0000000..5babd63 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelMode.cpp @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_modeBox + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../../../../utils/gui.h" +#include "../../../../core/graphics.h" +#include "../../../../core/sampleChannel.h" +#include "../../../../core/const.h" +#include "../../basics/boxtypes.h" +#include "channelMode.h" + + +geChannelMode::geChannelMode(int x, int y, int w, int h, SampleChannel *ch, + const char *L) + : Fl_Menu_Button(x, y, w, h, L), ch(ch) +{ + box(G_CUSTOM_BORDER_BOX); + textsize(GUI_FONT_SIZE_BASE); + textcolor(COLOR_TEXT_0); + color(COLOR_BG_0); + + add("Loop . basic", 0, cb_changeMode, (void *)LOOP_BASIC); + add("Loop . once", 0, cb_changeMode, (void *)LOOP_ONCE); + add("Loop . once . bar", 0, cb_changeMode, (void *)LOOP_ONCE_BAR); + add("Loop . repeat", 0, cb_changeMode, (void *)LOOP_REPEAT); + add("Oneshot . basic", 0, cb_changeMode, (void *)SINGLE_BASIC); + add("Oneshot . press", 0, cb_changeMode, (void *)SINGLE_PRESS); + add("Oneshot . retrig", 0, cb_changeMode, (void *)SINGLE_RETRIG); + add("Oneshot . endless", 0, cb_changeMode, (void *)SINGLE_ENDLESS); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelMode::draw() { + fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border + switch (ch->mode) { + case LOOP_BASIC: + fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1); + break; + case LOOP_ONCE: + fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1); + break; + case LOOP_ONCE_BAR: + fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1); + break; + case LOOP_REPEAT: + fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1); + break; + case SINGLE_BASIC: + fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1); + break; + case SINGLE_PRESS: + fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1); + break; + case SINGLE_RETRIG: + fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1); + break; + case SINGLE_ENDLESS: + fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1); + break; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelMode::cb_changeMode(Fl_Widget *v, void *p) { ((geChannelMode*)v)->__cb_changeMode((intptr_t)p); } + + +/* -------------------------------------------------------------------------- */ + + +void geChannelMode::__cb_changeMode(int mode) +{ + ch->mode = mode; + + /* what to do when the channel is playing and you change the mode? + * Nothing, since v0.5.3. Just refresh the action editor window, in + * case it's open */ + + gu_refreshActionEditor(); +} diff --git a/src/gui/elems/mainWindow/keyboard/channelMode.h b/src/gui/elems/mainWindow/keyboard/channelMode.h new file mode 100644 index 0000000..0829be9 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelMode.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_modeBox + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_CHANNEL_MODE_H +#define GE_CHANNEL_MODE_H + + +#include + + +class geChannelMode : public Fl_Menu_Button +{ +private: + + static void cb_changeMode (Fl_Widget *v, void *p); + inline void __cb_changeMode(int mode); + + class SampleChannel *ch; + +public: + + geChannelMode(int x, int y, int w, int h, class SampleChannel *ch, + const char *l=0); + void draw(); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/channelStatus.cpp b/src/gui/elems/mainWindow/keyboard/channelStatus.cpp new file mode 100644 index 0000000..bc89239 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelStatus.cpp @@ -0,0 +1,84 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_status + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../../../../core/mixer.h" +#include "../../../../core/sampleChannel.h" +#include "../../../../core/recorder.h" +#include "../../../../core/const.h" +#include "channelStatus.h" + + +extern Mixer G_Mixer; +extern Recorder G_Recorder; + + +geChannelStatus::geChannelStatus(int x, int y, int w, int h, SampleChannel *ch, + const char *L) + : Fl_Box(x, y, w, h, L), ch(ch) {} + + +/* -------------------------------------------------------------------------- */ + + +void geChannelStatus::draw() +{ + fl_rect(x(), y(), w(), h(), COLOR_BD_0); // reset border + fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // reset background + + if (ch != NULL) { + if (ch->status & (STATUS_WAIT | STATUS_ENDING | REC_ENDING | REC_WAITING) || + ch->recStatus & (REC_WAITING | REC_ENDING)) + { + fl_rect(x(), y(), w(), h(), COLOR_BD_1); + } + else + if (ch->status == STATUS_PLAY) + fl_rect(x(), y(), w(), h(), COLOR_BD_1); + else + fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // status empty + + + if (G_Mixer.recording && ch->armed) + fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3); // take in progress + else + if (G_Recorder.active && G_Recorder.canRec(ch, &G_Mixer)) + fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4); // action record + + /* equation for the progress bar: + * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */ + + int pos = ch->getPosition(); + if (pos == -1) + pos = 0; + else + pos = (pos * (w()-1)) / (ch->end - ch->begin); + fl_rectf(x()+1, y()+1, pos, h()-2, COLOR_BG_2); + } +} diff --git a/src/gui/elems/mainWindow/keyboard/channelStatus.h b/src/gui/elems/mainWindow/keyboard/channelStatus.h new file mode 100644 index 0000000..6e911cb --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/channelStatus.h @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_status + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_CHANNEL_STATUS_H +#define GE_CHANNEL_STATUS_H + + +#include + + +class geChannelStatus : public Fl_Box +{ +public: + geChannelStatus(int X, int Y, int W, int H, class SampleChannel *ch, + const char *L=0); + void draw(); + class SampleChannel *ch; +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/column.cpp b/src/gui/elems/mainWindow/keyboard/column.cpp new file mode 100644 index 0000000..6518aed --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/column.cpp @@ -0,0 +1,293 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_column + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/sampleChannel.h" +#include "../../../../glue/channel.h" +#include "../../../../utils/log.h" +#include "../../../../utils/string.h" +#include "../../../dialogs/gd_warnings.h" +#include "../../../elems/basics/boxtypes.h" +#include "keyboard.h" +#include "sampleChannel.h" +#include "midiChannel.h" +#include "column.h" + + +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 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 (gResizerBar). + 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 NULL: at this point (i.e the constructor) + geColumn is still detached from any parent. We use a custom geKeyboard *parent + instead. */ + + begin(); + addChannelBtn = new gClick(x(), y(), w(), 20, "Add new channel"); + end(); + + resizer = new gResizerBar(x()+w(), y(), 16, h(), false); + resizer->setMinSize(MIN_COLUMN_WIDTH); + parent->add(resizer); + + addChannelBtn->callback(cb_addChannel, (void*)this); +} + + +/* -------------------------------------------------------------------------- */ + + +geColumn::~geColumn() +{ + /* FIXME - this could actually cause a memory leak. resizer is + just removed, not deleted. But we cannot delete it right now. */ + + parent->remove(resizer); +} + + +/* -------------------------------------------------------------------------- */ + + + +int geColumn::handle(int e) +{ + switch (e) { + case FL_RELEASE: { + if (Fl::event_button() == FL_RIGHT_MOUSE) { + __cb_addChannel(); + return 1; + } + } + case FL_DND_ENTER: // return(1) for these events to 'accept' dnd + case FL_DND_DRAG: + case FL_DND_RELEASE: { + return 1; + } + case FL_PASTE: { // handle actual drop (paste) operation + vector paths; + gu_split(Fl::event_text(), "\n", &paths); + bool fails = false; + int result = 0; + for (unsigned i=0; iguiChannel); + fails = true; + } + } + if (fails) { + if (paths.size() > 1) + gdAlert("Some files were not loaded successfully."); + else + parent->printChannelMessage(result); + } + return 1; + } + } + + /* we return fl_Group::handle only if none of the cases above are fired. That + is because we don't want to propagate a dnd drop to all the sub widgets. */ + + return Fl_Group::handle(e); +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::resize(int X, int Y, int W, int H) +{ + /* resize all children */ + + int ch = children(); + for (int i=0; iresize(X, Y + (i * (c->h() + 4)), W, c->h()); + } + + /* resize group itself */ + + x(X); y(Y); w(W); h(H); + + /* resize resizerBar */ + + resizer->size(16, H); +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::refreshChannels() +{ + for (int i=1; irefresh(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::draw() +{ + fl_color(fl_rgb_color(27, 27, 27)); + fl_rectf(x(), y(), w(), h()); + + /* call draw and then redraw in order to avoid channel corruption when + scrolling horizontally */ + + for (int i=0; idraw(); + child(i)->redraw(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::cb_addChannel(Fl_Widget *v, void *p) { ((geColumn*)p)->__cb_addChannel(); } + + +/* -------------------------------------------------------------------------- */ + + +geChannel *geColumn::addChannel(Channel *ch) +{ + int currentY = y() + children() * 24; + geChannel *gch = NULL; + if (ch->type == CHANNEL_SAMPLE) + gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); + else + gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); + + add(gch); + resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop + gch->redraw(); // avoid corruption + parent->redraw(); // redraw Keyboard + return gch; +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::deleteChannel(geChannel *gch) +{ + 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; iposition(gch->x(), y()+(i*24)); + } + size(w(), children() * 24 + 66); // evil space for drag n drop + redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::__cb_addChannel() +{ + gu_log("[geColumn::__cb_addChannel] index = %d\n", index); + int type = openTypeMenu(); + if (type) + glue_addChannel(index, type); +} + + +/* -------------------------------------------------------------------------- */ + + +int geColumn::openTypeMenu() +{ + Fl_Menu_Item rclick_menu[] = { + {"Sample channel"}, + {"MIDI channel"}, + {0} + }; + + Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); + b->box(G_CUSTOM_BORDER_BOX); + b->textsize(GUI_FONT_SIZE_BASE); + b->textcolor(COLOR_TEXT_0); + b->color(COLOR_BG_0); + + const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); + if (!m) return 0; + + if (strcmp(m->label(), "Sample channel") == 0) + return CHANNEL_SAMPLE; + if (strcmp(m->label(), "MIDI channel") == 0) + return CHANNEL_MIDI; + return 0; +} + + +/* -------------------------------------------------------------------------- */ + + +void geColumn::clear(bool full) +{ + if (full) + Fl_Group::clear(); + else { + while (children() >= 2) { // skip "add new channel" btn + int i = children()-1; + deleteChannel((geChannel*)child(i)); + } + } +} + + +/* -------------------------------------------------------------------------- */ + + +Channel *geColumn::getChannel(int i) +{ + geChannel *gch = (geChannel*) child(i); + if (gch->type == CHANNEL_SAMPLE) + return ((geSampleChannel*) child(i))->ch; + else + return ((geMidiChannel*) child(i))->ch; +} diff --git a/src/gui/elems/mainWindow/keyboard/column.h b/src/gui/elems/mainWindow/keyboard/column.h new file mode 100644 index 0000000..1d78540 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/column.h @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_column + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_COLUMN_H +#define GE_COLUMN_H + + +#include + + +class geColumn : public Fl_Group +{ +private: + + static void cb_addChannel (Fl_Widget *v, void *p); + inline void __cb_addChannel(); + + int openTypeMenu(); + + class gClick *addChannelBtn; + class gResizerBar *resizer; + class geKeyboard *parent; + + int index; + +public: + + geColumn(int x, int y, int w, int h, int index, class geKeyboard *parent); + ~geColumn(); + + /* addChannel + * add a new channel in this column and set the internal pointer + * to channel to 'ch'. */ + + class geChannel *addChannel(class Channel *ch); + + /* handle */ + + int handle(int e); + + /* resize + * custom resize behavior. */ + + void resize(int x, int y, int w, int h); + + /* deleteChannel + * remove the channel 'gch' from this column. */ + + void deleteChannel(geChannel *gch); + + /* refreshChannels + * update 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(); } +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/keyboard.cpp b/src/gui/elems/mainWindow/keyboard/keyboard.cpp new file mode 100644 index 0000000..00d2bef --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/keyboard.cpp @@ -0,0 +1,405 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gg_keyboard + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/sampleChannel.h" +#include "../../../../glue/main.h" +#include "../../../../glue/io.h" +#include "../../../../utils/log.h" +#include "../../../dialogs/gd_warnings.h" +#include "../../basics/boxtypes.h" +#include "column.h" +#include "sampleChannel.h" +#include "keyboard.h" + + +int geKeyboard::indexColumn = 0; + + +/* -------------------------------------------------------------------------- */ + + +geKeyboard::geKeyboard(int X, int Y, int W, int H) +: Fl_Scroll (X, Y, W, H), + bckspcPressed(false), + endPressed (false), + spacePressed (false), + addColumnBtn (NULL) +{ + color(COLOR_BG_MAIN); + type(Fl_Scroll::BOTH_ALWAYS); + scrollbar.color(COLOR_BG_0); + scrollbar.selection_color(COLOR_BG_1); + scrollbar.labelcolor(COLOR_BD_1); + scrollbar.slider(G_CUSTOM_BORDER_BOX); + hscrollbar.color(COLOR_BG_0); + hscrollbar.selection_color(COLOR_BG_1); + hscrollbar.labelcolor(COLOR_BD_1); + hscrollbar.slider(G_CUSTOM_BORDER_BOX); + + addColumnBtn = new gClick(8, y(), 200, 20, "Add new column"); + addColumnBtn->callback(cb_addColumn, (void*) this); + add(addColumnBtn); + + init(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::init() +{ + /* add 6 empty columns as init layout */ + + __cb_addColumn(); + __cb_addColumn(); + __cb_addColumn(); + __cb_addColumn(); + __cb_addColumn(); + __cb_addColumn(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::freeChannel(geChannel *gch) +{ + gch->reset(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::deleteChannel(geChannel *gch) +{ + for (unsigned i=0; ifind(gch); + if (k != columns.at(i)->children()) { + columns.at(i)->deleteChannel(gch); + return; + } + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::updateChannel(geChannel *gch) +{ + gch->update(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::organizeColumns() +{ + /* if only one column exists don't cleanup: the initial column must + * stay here. */ + + if (columns.size() == 1) + return; + + /* otherwise delete all empty columns */ + /** FIXME - this for loop might not work correctly! */ + + for (unsigned i=columns.size()-1; i>=1; i--) { + if (columns.at(i)->isEmpty()) { + //Fl::delete_widget(columns.at(i)); + delete columns.at(i); + columns.erase(columns.begin() + i); + } + } + + /* compact column, avoid empty spaces */ + + for (unsigned i=1; iposition(columns.at(i-1)->x() + columns.at(i-1)->w() + 16, y()); + + addColumnBtn->position(columns.back()->x() + columns.back()->w() + 16, y()); + + /* recompute col indexes */ + + refreshColIndexes(); + + redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::cb_addColumn(Fl_Widget *v, void *p) +{ + ((geKeyboard*)p)->__cb_addColumn(DEFAULT_COLUMN_WIDTH); +} + + +/* -------------------------------------------------------------------------- */ + + +geChannel *geKeyboard::addChannel(int colIndex, Channel *ch, bool build) +{ + geColumn *col = getColumnByIndex(colIndex); + + /* no column with index 'colIndex' found? Just create it and set its index + to 'colIndex'. */ + + if (!col) { + __cb_addColumn(); + col = columns.back(); + col->setIndex(colIndex); + 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); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::refreshColumns() +{ + for (unsigned i=0; irefreshChannels(); +} + + +/* -------------------------------------------------------------------------- */ + + +geColumn *geKeyboard::getColumnByIndex(int index) +{ + for (unsigned i=0; igetIndex() == index) + return columns.at(i); + return NULL; +} + + +/* -------------------------------------------------------------------------- */ + +/* TODO - the following event handling for play, stop, rewind, start rec and +so on should be moved to the proper widget: gdMainWindow or (better) geController. */ + +int geKeyboard::handle(int e) +{ + int ret = Fl_Group::handle(e); // assume the buttons won't handle the Keyboard events + switch (e) { + case FL_FOCUS: + case FL_UNFOCUS: { + ret = 1; // enables receiving Keyboard events + break; + } + case FL_SHORTCUT: // in case widget that isn't ours has focus + case FL_KEYDOWN: // Keyboard key pushed + case FL_KEYUP: { // Keyboard key released + + /* rewind session. Avoid retrigs */ + + if (e == FL_KEYDOWN) { + if (Fl::event_key() == FL_BackSpace && !bckspcPressed) { + bckspcPressed = true; + glue_rewindSeq(); + ret = 1; + break; + } + else if (Fl::event_key() == FL_End && !endPressed) { + endPressed = true; + glue_startStopInputRec(false); // update gui + ret = 1; + break; + } + else if (Fl::event_key() == FL_Enter && !enterPressed) { + enterPressed = true; + glue_startStopActionRec(false); // update gui + ret = 1; + break; + } + else if (Fl::event_key() == ' ' && !spacePressed) { + spacePressed = true; + glue_startStopSeq(false); // update gui + ret = 1; + break; + } + } + else if (e == FL_KEYUP) { + if (Fl::event_key() == FL_BackSpace) + bckspcPressed = false; + else if (Fl::event_key() == FL_End) + endPressed = false; + else if (Fl::event_key() == ' ') + spacePressed = false; + else if (Fl::event_key() == FL_Enter) + enterPressed = false; + } + + /* Walk button arrays, trying to match button's label with the Keyboard event. + * If found, set that button's value() based on up/down event, + * and invoke that button's callback() */ + + for (unsigned i=0; ichildren(); k++) + ret &= ((geChannel*)columns.at(i)->child(k))->keyPress(e); + break; + } + } + return ret; +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::clear() +{ + for (unsigned i=0; iposition(8, y()); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::setChannelWithActions(geSampleChannel *gch) +{ + if (gch->ch->hasActions) + gch->showActionButton(); + else + gch->hideActionButton(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::printChannelMessage(int res) +{ + if (res == SAMPLE_NOT_VALID) + gdAlert("This is not a valid WAVE file."); + else if (res == SAMPLE_MULTICHANNEL) + gdAlert("Multichannel samples not supported."); + else if (res == SAMPLE_WRONG_BIT) + gdAlert("This sample has an\nunsupported bit-depth (> 32 bit)."); + else if (res == SAMPLE_WRONG_ENDIAN) + gdAlert("This sample has a wrong\nbyte order (not little-endian)."); + else if (res == SAMPLE_WRONG_FORMAT) + gdAlert("This sample is encoded in\nan unsupported audio format."); + else if (res == SAMPLE_READ_ERROR) + gdAlert("Unable to read this sample."); + else if (res == SAMPLE_PATH_TOO_LONG) + gdAlert("File path too long."); + else + gdAlert("Unknown error."); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::__cb_addColumn(int width) +{ + int colx; + int colxw; + int gap = 16; + if (columns.size() == 0) { + colx = x() - xposition(); // mind the offset with xposition() + colxw = colx + width; + } + else { + geColumn *prev = columns.back(); + colx = prev->x()+prev->w() + gap; + colxw = colx + width; + } + + /* add geColumn to geKeyboard and to columns vector */ + + geColumn *gc = new geColumn(colx, y(), width, 2000, indexColumn, this); + add(gc); + columns.push_back(gc); + indexColumn++; + + /* move addColumn button */ + + addColumnBtn->position(colxw + gap, y()); + redraw(); + + gu_log("[geKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", + gc->getIndex(), width, columns.size(), addColumnBtn->x()); + + /* recompute col indexes */ + + refreshColIndexes(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::addColumn(int width) +{ + __cb_addColumn(width); +} + + +/* -------------------------------------------------------------------------- */ + + +void geKeyboard::refreshColIndexes() +{ + for (unsigned i=0; isetIndex(i); +} + + +/* -------------------------------------------------------------------------- */ + + +int geKeyboard::getColumnWidth(int i) +{ + return getColumnByIndex(i)->w(); +} + + +/* -------------------------------------------------------------------------- */ + + +geColumn *geKeyboard::getColumn(int i) +{ + return columns.at(i); +} diff --git a/src/gui/elems/mainWindow/keyboard/keyboard.h b/src/gui/elems/mainWindow/keyboard/keyboard.h new file mode 100644 index 0000000..8778c2a --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/keyboard.h @@ -0,0 +1,158 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gg_keyboard + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_KEYBOARD_H +#define GE_KEYBOARD_H + + +#include +#include +#include "../../../../core/const.h" + + +class geKeyboard : public Fl_Scroll +{ +private: + + /* refreshColIndexes + * Recompute all column indexes in order to avoid any gaps between them. + * Indexes must always be contiguous! */ + + void refreshColIndexes(); + + static void cb_addColumn (Fl_Widget *v, void *p); + inline void __cb_addColumn(int width=DEFAULT_COLUMN_WIDTH); + + bool bckspcPressed; + bool endPressed; + bool spacePressed; + bool enterPressed; + + /* indexColumn + * the last index used for column. */ + + static int indexColumn; + + class gClick *addColumnBtn; + + /* columns + * a vector of columns which in turn contain channels. */ + + std::vector columns; + +public: + + geKeyboard(int X, int Y, int W, int H); + + int handle(int e); + + /* init + * build the initial setup of empty channels. */ + + 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. */ + + class geChannel *addChannel(int column, class Channel *ch, bool build=false); + + /* addColumn + * add a new column to the top of the stack. */ + + void addColumn(int width=380); + + /* deleteChannel + * delete a channel from geChannels<> where geChannel->ch == ch and remove + * it from the stack. */ + + void deleteChannel(geChannel *gch); + + /* freeChannel + * free a channel from geChannels<> where geChannel->ch == ch. No channels + * are deleted */ + + void freeChannel(geChannel *gch); + + /* updateChannel + * wrapper function to call gch->update(). */ + + void updateChannel(geChannel *gch); + + /* organizeColumns + * reorganize columns layout by removing empty gaps. */ + + void organizeColumns(); + + /* refreshColumns + * refresh each column's channel, called on each GUI cycle. */ + + void refreshColumns(); + + /* getColumnByIndex + * return the column with index 'index', or NULL if not found. */ + + geColumn *getColumnByIndex(int index); + + /* getColumn + * return the column with from columns->at(i). */ + + geColumn *getColumn(int i); + + /* clear + * delete all channels and groups. */ + + void clear(); + + /* setChannelWithActions + * add 'R' button if channel has actions, and set recorder to active. */ + + void setChannelWithActions(class geSampleChannel *gch); + + /* printChannelMessage + * given any output by glue_loadChannel, print the message on screen + * on a gdAlert subwindow. */ + + void printChannelMessage(int res); + + /* getTotalColumns */ + + unsigned getTotalColumns() { return columns.size(); } + + /* getColumnWidth + * return the width in pixel of i-th column. Warning: 'i' is the i-th column + * in the column array, NOT the index. */ + + int getColumnWidth(int i); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/midiChannel.cpp b/src/gui/elems/mainWindow/keyboard/midiChannel.cpp new file mode 100644 index 0000000..183bc71 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/midiChannel.cpp @@ -0,0 +1,284 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_midiChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/const.h" +#include "../../../../core/graphics.h" +#include "../../../../core/midiChannel.h" +#include "../../../../glue/channel.h" +#include "../../../../glue/io.h" +#include "../../../dialogs/gd_mainWindow.h" +#include "../../../dialogs/gd_editor.h" +#include "../../../dialogs/gd_actionEditor.h" +#include "../../../dialogs/gd_warnings.h" +#include "../../../dialogs/gd_browser.h" +#include "../../../dialogs/gd_keyGrabber.h" +#include "../../../dialogs/gd_pluginList.h" +#include "../../../dialogs/midiIO/midiInputChannel.h" +#include "../../../dialogs/midiIO/midiOutputMidiCh.h" +#include "../../basics/boxtypes.h" +#include "midiChannel.h" + + +extern Recorder G_Recorder; +extern gdMainWindow *G_MainWin; + + +geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch) + : geChannel(X, Y, W, H, CHANNEL_MIDI, ch) +{ + begin(); + +#if defined(WITH_VST) + int delta = 144; // (6 widgets * 20) + (6 paddings * 4) +#else + int delta = 120; // (5 widgets * 20) + (5 paddings * 4) +#endif + + button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); + arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); + mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --"); + mute = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); + solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); +#if defined(WITH_VST) + fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); + vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); +#else + vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); +#endif + + end(); + + resizable(mainButton); + + update(); + + button->callback(cb_button, (void*)this); + button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease + + arm->type(FL_TOGGLE_BUTTON); + arm->callback(cb_arm, (void*)this); + +#ifdef WITH_VST + fx->callback(cb_openFxWindow, (void*)this); +#endif + + mute->type(FL_TOGGLE_BUTTON); + mute->callback(cb_mute, (void*)this); + + solo->type(FL_TOGGLE_BUTTON); + solo->callback(cb_solo, (void*)this); + + mainButton->callback(cb_openMenu, (void*)this); + + vol->callback(cb_changeVol, (void*)this); + + ch->guiChannel = this; +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::cb_button (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_button(); } +void geMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_openMenu(); } + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::__cb_button() +{ + if (button->value()) + glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::__cb_openMenu() +{ + Fl_Menu_Item rclick_menu[] = { + {"Edit actions..."}, // 0 + {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 1 + {"All"}, // 2 + {0}, // 3 + {"Setup keyboard input..."}, // 5 + {"Setup MIDI input..."}, // 6 + {"Setup MIDI output..."}, // 7 + {"Clone channel"}, // 8 + {"Delete channel"}, // 9 + {0} + }; + + /* no 'clear actions' if there are no actions */ + + if (!ch->hasActions) + rclick_menu[1].deactivate(); + + Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); + b->box(G_CUSTOM_BORDER_BOX); + b->textsize(GUI_FONT_SIZE_BASE); + b->textcolor(COLOR_TEXT_0); + b->color(COLOR_BG_0); + + const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); + if (!m) return; + + if (strcmp(m->label(), "Delete channel") == 0) { + if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) + return; + glue_deleteChannel(ch); + return; + } + + if (strcmp(m->label(), "Clone channel") == 0) { + glue_cloneChannel(ch); + return; + } + + if (strcmp(m->label(), "Setup keyboard input...") == 0) { + gu_openSubWindow(G_MainWin, new gdKeyGrabber(ch), 0); + //new gdKeyGrabber(ch); + return; + } + + if (strcmp(m->label(), "All") == 0) { + if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) + return; + G_Recorder.clearChan(ch->index); + ch->hasActions = false; + gu_refreshActionEditor(); // refresh a.editor window, it could be open + return; + } + + if (strcmp(m->label(), "Edit actions...") == 0) { + gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); + return; + } + + if (strcmp(m->label(), "Setup MIDI input...") == 0) { + gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); + return; + } + + if (strcmp(m->label(), "Setup MIDI output...") == 0) { + //gu_openSubWindow(G_MainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); + gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh((MidiChannel*) ch), 0); + return; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::refresh() +{ + setColorsByStatus(ch->status, ch->recStatus); + mainButton->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::reset() +{ + mainButton->setDefaultMode("-- MIDI --"); + mainButton->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::update() +{ + if (((MidiChannel*) ch)->midiOut) { + char tmp[32]; + sprintf(tmp, "-- MIDI (channel %d) --", ((MidiChannel*) ch)->midiOutChan+1); + mainButton->copy_label(tmp); + } + else + mainButton->label("-- MIDI --"); + + vol->value(ch->volume); + mute->value(ch->mute); + solo->value(ch->solo); + + mainButton->setKey(ch->key); + +#ifdef WITH_VST + fx->full = ch->plugins.size() > 0; + fx->redraw(); +#endif +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiChannel::resize(int X, int Y, int W, int H) +{ + geChannel::resize(X, Y, W, H); + + arm->hide(); +#ifdef WITH_VST + fx->hide(); +#endif + + if (w() > BREAK_ARM) + arm->show(); +#ifdef WITH_VST + if (w() > BREAK_FX) + fx->show(); +#endif + + packWidgets(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char *l) + : geChannelButton(x, y, w, h, l) {} + + +/* -------------------------------------------------------------------------- */ + + +int geMidiChannelButton::handle(int e) +{ + // MIDI drag-n-drop does nothing so far. + return gClick::handle(e); +} diff --git a/src/gui/elems/mainWindow/keyboard/midiChannel.h b/src/gui/elems/mainWindow/keyboard/midiChannel.h new file mode 100644 index 0000000..cd06ddc --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/midiChannel.h @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_midiChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_MIDI_CHANNEL_H +#define GE_MIDI_CHANNEL_H + + +#include "channel.h" +#include "channelButton.h" + + +class geMidiChannel : public geChannel +{ +private: + + static void cb_button (Fl_Widget *v, void *p); + static void cb_openMenu (Fl_Widget *v, void *p); + + inline void __cb_button (); + inline void __cb_openMenu (); + inline void __cb_readActions (); + +public: + + geMidiChannel(int x, int y, int w, int h, class MidiChannel *ch); + + void reset (); + void update (); + void refresh (); + int keyPress(int event); // TODO - move to base class + void resize (int x, int y, int w, int h); +}; + + +/* -------------------------------------------------------------------------- */ + + +class geMidiChannelButton : public geChannelButton +{ +public: + geMidiChannelButton(int x, int y, int w, int h, const char *l=0); + int handle(int e); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp b/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp new file mode 100644 index 0000000..fa3289c --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp @@ -0,0 +1,499 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_sampleChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../../core/mixer.h" +#include "../../../../core/conf.h" +#include "../../../../core/recorder.h" +#include "../../../../core/graphics.h" +#include "../../../../core/wave.h" +#include "../../../../core/sampleChannel.h" +#include "../../../../glue/main.h" +#include "../../../../glue/io.h" +#include "../../../../glue/channel.h" +#include "../../../../glue/storage.h" +#include "../../../../utils/string.h" +#include "../../../dialogs/gd_mainWindow.h" +#include "../../../dialogs/gd_keyGrabber.h" +#include "../../../dialogs/gd_editor.h" +#include "../../../dialogs/gd_actionEditor.h" +#include "../../../dialogs/gd_warnings.h" +#include "../../../dialogs/gd_browser.h" +#include "../../../dialogs/midiIO/midiOutputSampleCh.h" +#include "../../../dialogs/midiIO/midiInputChannel.h" +#include "../../basics/boxtypes.h" +#include "channelStatus.h" +#include "channelMode.h" +#include "keyboard.h" +#include "sampleChannel.h" + + +extern Mixer G_Mixer; +extern Conf G_Conf; +extern Recorder G_Recorder; +extern gdMainWindow *G_MainWin; + + +geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch) + : geChannel(X, Y, W, H, CHANNEL_SAMPLE, (Channel*) ch) +{ + begin(); + + button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); + arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); + status = new 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 gClick(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 gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); + solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); +#ifdef WITH_VST + fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); + vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); +#else + vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); +#endif + + end(); + + resizable(mainButton); + + update(); + + button->callback(cb_button, (void*)this); + button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease + + arm->type(FL_TOGGLE_BUTTON); + arm->callback(cb_arm, (void*)this); + +#ifdef WITH_VST + fx->callback(cb_openFxWindow, (void*)this); +#endif + + mute->type(FL_TOGGLE_BUTTON); + mute->callback(cb_mute, (void*)this); + + solo->type(FL_TOGGLE_BUTTON); + solo->callback(cb_solo, (void*)this); + + mainButton->callback(cb_openMenu, (void*)this); + + readActions->type(FL_TOGGLE_BUTTON); + readActions->value(ch->readActions); + readActions->callback(cb_readActions, (void*)this); + + vol->callback(cb_changeVol, (void*)this); + + ch->guiChannel = this; +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::cb_button (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); } +void geSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); } +void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); } + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::__cb_button() +{ + if (button->value()) // pushed + glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); + else // released + glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift()); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::__cb_openMenu() +{ + /* If you're recording (input or actions) no menu is allowed; you can't do + anything, especially deallocate the channel */ + + if (G_Mixer.recording || G_Recorder.active) + return; + + /* the following is a trash workaround for a FLTK menu. We need a gMenu + * widget asap */ + + Fl_Menu_Item rclick_menu[] = { + {"Load new sample..."}, // 0 + {"Export sample to file..."}, // 1 + {"Setup keyboard input..."}, // 2 + {"Setup MIDI input..."}, // 3 + {"Setup MIDI output..."}, // 4 + {"Edit sample..."}, // 5 + {"Edit actions..."}, // 6 + {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 7 + {"All"}, // 8 + {"Mute"}, // 9 + {"Volume"}, // 10 + {"Start/Stop"}, // 11 + {0}, // 12 + {"Clone channel"}, // 13 + {"Free channel"}, // 14 + {"Delete channel"}, // 15 + {0} + }; + + if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) { + rclick_menu[1].deactivate(); + rclick_menu[5].deactivate(); + rclick_menu[14].deactivate(); + } + + /* no 'clear actions' if there are no actions */ + + if (!ch->hasActions) + rclick_menu[7].deactivate(); + + /* no 'clear start/stop actions' for those channels in loop mode: + * they cannot have start/stop actions. */ + + if (((SampleChannel*)ch)->mode & LOOP_ANY) + rclick_menu[11].deactivate(); + + Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); + b->box(G_CUSTOM_BORDER_BOX); + b->textsize(GUI_FONT_SIZE_BASE); + b->textcolor(COLOR_TEXT_0); + b->color(COLOR_BG_0); + + const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); + if (!m) return; + + if (strcmp(m->label(), "Load new sample...") == 0) { + gWindow *w = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Browse sample", + G_Conf.samplePath.c_str(), glue_loadSample, ch); + gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER); + return; + } + + if (strcmp(m->label(), "Setup keyboard input...") == 0) { + new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow + return; + } + + if (strcmp(m->label(), "Setup MIDI input...") == 0) { + gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); + return; + } + + if (strcmp(m->label(), "Setup MIDI output...") == 0) { + gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh((SampleChannel*) ch), 0); + return; + } + + if (strcmp(m->label(), "Edit sample...") == 0) { + gu_openSubWindow(G_MainWin, new gdEditor((SampleChannel*) ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor + return; + } + + if (strcmp(m->label(), "Export sample to file...") == 0) { + gWindow *w = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Save sample", \ + G_Conf.samplePath.c_str(), "", glue_saveSample, ch); + gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER); + return; + } + + if (strcmp(m->label(), "Delete channel") == 0) { + if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) + return; + glue_deleteChannel(ch); + return; + } + + if (strcmp(m->label(), "Free channel") == 0) { + if (ch->status == STATUS_PLAY) { + if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?")) + return; + } + else if (!gdConfirmWin("Warning", "Free channel: are you sure?")) + return; + + glue_freeChannel(ch); + + /* delete any related subwindow */ + + /** FIXME - use gu_closeAllSubwindows() */ + + G_MainWin->delSubWindow(WID_FILE_BROWSER); + G_MainWin->delSubWindow(WID_ACTION_EDITOR); + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); + G_MainWin->delSubWindow(WID_FX_LIST); + + return; + } + + if (strcmp(m->label(), "Clone channel") == 0) { + glue_cloneChannel(ch); + return; + } + + if (strcmp(m->label(), "Mute") == 0) { + if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?")) + return; + G_Recorder.clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF); + ch->hasActions = G_Recorder.hasActions(ch->index); + + if (!ch->hasActions) + hideActionButton(); + + /* TODO - set mute=false */ + + gu_refreshActionEditor(); // refresh a.editor window, it could be open + return; + } + + if (strcmp(m->label(), "Start/Stop") == 0) { + if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?")) + return; + G_Recorder.clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN); + ch->hasActions = G_Recorder.hasActions(ch->index); + + if (!ch->hasActions) + hideActionButton(); + gu_refreshActionEditor(); // refresh a.editor window, it could be open + return; + } + + if (strcmp(m->label(), "Volume") == 0) { + if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?")) + return; + G_Recorder.clearAction(ch->index, ACTION_VOLUME); + ch->hasActions = G_Recorder.hasActions(ch->index); + if (!ch->hasActions) + hideActionButton(); + gu_refreshActionEditor(); // refresh a.editor window, it could be open + return; + } + + if (strcmp(m->label(), "All") == 0) { + if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) + return; + G_Recorder.clearChan(ch->index); + ch->hasActions = false; + hideActionButton(); + gu_refreshActionEditor(); // refresh a.editor window, it could be open + return; + } + + if (strcmp(m->label(), "Edit actions...") == 0) { + gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); + return; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::__cb_readActions() +{ + glue_startStopReadingRecs((SampleChannel*) ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::refresh() +{ + if (!mainButton->visible()) // mainButton invisible? status too (see below) + return; + + setColorsByStatus(ch->status, ch->recStatus); + + if (((SampleChannel*) ch)->wave != NULL) { + if (G_Mixer.recording && ch->armed) + mainButton->setInputRecordMode(); + if (G_Recorder.active) { + if (G_Recorder.canRec(ch, &G_Mixer)) + mainButton->setActionRecordMode(); + } + status->redraw(); // status invisible? sampleButton too (see below) + } + mainButton->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::reset() +{ + hideActionButton(); + mainButton->setDefaultMode("-- no sample --"); + mainButton->redraw(); + status->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::update() +{ + /* update sample button's label */ + + switch (ch->status) { + case STATUS_EMPTY: + mainButton->label("-- no sample --"); + break; + case STATUS_MISSING: + case STATUS_WRONG: + mainButton->label("* file not found! *"); + break; + default: + mainButton->label(((SampleChannel*) ch)->wave->name.c_str()); + break; + } + + /* update channels. If you load a patch with recorded actions, the 'R' + * button must be shown. Moreover if the actions are active, the 'R' + * button must be activated accordingly. */ + + if (ch->hasActions) + showActionButton(); + else + hideActionButton(); + + /* updates modebox */ + + modeBox->value(((SampleChannel*) ch)->mode); + modeBox->redraw(); + + /* update volumes+mute+solo */ + + vol->value(ch->volume); + mute->value(ch->mute); + solo->value(ch->solo); + + mainButton->setKey(ch->key); + +#ifdef WITH_VST + fx->full = ch->plugins.size() > 0; + fx->redraw(); +#endif +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::showActionButton() +{ + readActions->value(((SampleChannel*) ch)->readActions); + readActions->show(); + packWidgets(); + redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::hideActionButton() +{ + readActions->hide(); + packWidgets(); + redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geSampleChannel::resize(int X, int Y, int W, int H) +{ + geChannel::resize(X, Y, W, H); + + arm->hide(); + modeBox->hide(); + readActions->hide(); +#ifdef WITH_VST + fx->hide(); +#endif + + if (w() > BREAK_ARM) + arm->show(); +#ifdef WITH_VST + if (w() > BREAK_FX) + fx->show(); +#endif + if (w() > BREAK_MODE_BOX) + modeBox->show(); + if (w() > BREAK_READ_ACTIONS && ch->hasActions) + readActions->show(); + + packWidgets(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const char *l) + : geChannelButton(x, y, w, h, l) {} + + +/* -------------------------------------------------------------------------- */ + + +int geSampleChannelButton::handle(int e) +{ + int ret = gClick::handle(e); + switch (e) { + case FL_DND_ENTER: + case FL_DND_DRAG: + case FL_DND_RELEASE: { + ret = 1; + break; + } + case FL_PASTE: { + geSampleChannel *gch = (geSampleChannel*) parent(); // parent is geSampleChannel + SampleChannel *ch = (SampleChannel*) gch->ch; + int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str()); + if (result != SAMPLE_LOADED_OK) + G_MainWin->keyboard->printChannelMessage(result); + ret = 1; + break; + } + } + return ret; +} diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannel.h b/src/gui/elems/mainWindow/keyboard/sampleChannel.h new file mode 100644 index 0000000..5c52151 --- /dev/null +++ b/src/gui/elems/mainWindow/keyboard/sampleChannel.h @@ -0,0 +1,81 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_sampleChannel + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_SAMPLE_CHANNEL_H +#define GE_SAMPLE_CHANNEL_H + + +#include "channel.h" +#include "channelButton.h" + + +class geSampleChannel : public geChannel +{ +private: + + static void cb_button (Fl_Widget *v, void *p); + static void cb_openMenu (Fl_Widget *v, void *p); + static void cb_readActions (Fl_Widget *v, void *p); + + inline void __cb_button (); + inline void __cb_openMenu (); + inline void __cb_readActions (); + +public: + + geSampleChannel(int x, int y, int w, int h, class SampleChannel *ch); + + void reset (); + void update (); + void refresh (); + void resize (int x, int y, int w, int h); + + /* show/hideActionButton + Adds or removes 'R' button when actions are available. */ + + void showActionButton(); + void hideActionButton(); + + class geChannelMode *modeBox; + class gClick *readActions; +}; + + +/* -------------------------------------------------------------------------- */ + + +class geSampleChannelButton : public geChannelButton +{ +public: + geSampleChannelButton(int x, int y, int w, int h, const char *l=0); + int handle(int e); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/mainIO.cpp b/src/gui/elems/mainWindow/mainIO.cpp new file mode 100644 index 0000000..7e61889 --- /dev/null +++ b/src/gui/elems/mainWindow/mainIO.cpp @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------------------- +* +* Giada - Your Hardcore Loopmachine +* +* mainIO +* +* ----------------------------------------------------------------------------- +* +* Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual +* +* This file is part of Giada - Your Hardcore Loopmachine. +* +* Giada - Your Hardcore Loopmachine is free software: you can +* redistribute it and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later version. +* +* Giada - Your Hardcore Loopmachine is distributed in the hope that it +* will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Giada - Your Hardcore Loopmachine. If not, see +* . +* +* -------------------------------------------------------------------------- */ + + +#include "../../../core/const.h" +#include "../../../core/graphics.h" +#include "../../../core/mixer.h" +#include "../../../core/pluginHost.h" +#include "../../../glue/main.h" +#include "../../../utils/gui.h" +#include "../../elems/ge_mixed.h" +#include "../../dialogs/gd_mainWindow.h" +#include "../../dialogs/gd_pluginList.h" +#include "mainIO.h" + + +extern Mixer G_Mixer; +extern gdMainWindow *G_MainWin; + + +geMainIO::geMainIO(int x, int y) + : Fl_Group(x, y, 396, 20) +{ + begin(); + +#if defined(WITH_VST) + masterFxIn = new gFxButton (x, y, 20, 20, fxOff_xpm, fxOn_xpm); + inVol = new gDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20); + inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+4, 140, 12); + inToOut = new gClick (inMeter->x()+inMeter->w()+4, y+4, 12, 12, "", inputToOutputOff_xpm, inputToOutputOn_xpm); + outMeter = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+4, 140, 12); + outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); + masterFxOut = new gFxButton (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm); +#else + inVol = new gDial (x+62, y, 20, 20); + inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 12); + outMeter = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 12); + outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); +#endif + + end(); + + resizable(NULL); // don't resize any widget + + outVol->callback(cb_outVol, (void*)this); + outVol->value(G_Mixer.outVol); + inVol->callback(cb_inVol, (void*)this); + inVol->value(G_Mixer.inVol); + +#ifdef WITH_VST + masterFxOut->callback(cb_masterFxOut, (void*)this); + masterFxIn->callback(cb_masterFxIn, (void*)this); + inToOut->callback(cb_inToOut, (void*)this); + inToOut->type(FL_TOGGLE_BUTTON); +#endif +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainIO::cb_outVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_outVol(); } +void geMainIO::cb_inVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_inVol(); } +#ifdef WITH_VST +void geMainIO::cb_masterFxOut(Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_masterFxOut(); } +void geMainIO::cb_masterFxIn (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_masterFxIn(); } +void geMainIO::cb_inToOut (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_inToOut(); } +#endif + + +/* -------------------------------------------------------------------------- */ + + +void geMainIO::__cb_outVol() +{ + glue_setOutVol(outVol->value()); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainIO::__cb_inVol() +{ + glue_setInVol(inVol->value()); +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST +void geMainIO::__cb_masterFxOut() +{ + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST); +} + +void geMainIO::__cb_masterFxIn() +{ + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST); +} + +void geMainIO::__cb_inToOut() +{ + G_Mixer.inToOut = inToOut->value(); +} +#endif + + +/* -------------------------------------------------------------------------- */ + + +void geMainIO::setOutVol(float v) +{ + outVol->value(v); +} + + +void geMainIO::setInVol(float v) +{ + inVol->value(v); +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST + +void geMainIO::setMasterFxOutFull(bool v) +{ + masterFxOut->full = v; + masterFxOut->redraw(); +} + + +void geMainIO::setMasterFxInFull(bool v) +{ + masterFxIn->full = v; + masterFxIn->redraw(); +} + +#endif + + +/* -------------------------------------------------------------------------- */ + + +void geMainIO::refresh() +{ + outMeter->mixerPeak = G_Mixer.peakOut; + inMeter->mixerPeak = G_Mixer.peakIn; + outMeter->redraw(); + inMeter->redraw(); +} diff --git a/src/gui/elems/mainWindow/mainIO.h b/src/gui/elems/mainWindow/mainIO.h new file mode 100644 index 0000000..f275211 --- /dev/null +++ b/src/gui/elems/mainWindow/mainIO.h @@ -0,0 +1,81 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainIO + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_MAIN_IO_H +#define GE_MAIN_IO_H + + +#include + + +class geMainIO : public Fl_Group +{ +private: + + class gSoundMeter *outMeter; + class gSoundMeter *inMeter; + class gDial *outVol; + class gDial *inVol; +#ifdef WITH_VST + class gFxButton *masterFxOut; + class gFxButton *masterFxIn; + class gClick *inToOut; +#endif + + static void cb_outVol (Fl_Widget *v, void *p); + static void cb_inVol (Fl_Widget *v, void *p); +#ifdef WITH_VST + static void cb_masterFxOut(Fl_Widget *v, void *p); + static void cb_masterFxIn (Fl_Widget *v, void *p); + static void cb_inToOut (Fl_Widget *v, void *p); +#endif + + inline void __cb_outVol (); + inline void __cb_inVol (); +#ifdef WITH_VST + inline void __cb_masterFxOut(); + inline void __cb_masterFxIn (); + inline void __cb_inToOut (); +#endif + +public: + + geMainIO(int x, int y); + + void refresh(); + + void setOutVol(float v); + void setInVol (float v); +#ifdef WITH_VST + void setMasterFxOutFull(bool v); + void setMasterFxInFull(bool v); +#endif +}; + +#endif diff --git a/src/gui/elems/mainWindow/mainMenu.cpp b/src/gui/elems/mainWindow/mainMenu.cpp new file mode 100644 index 0000000..5c9a0f4 --- /dev/null +++ b/src/gui/elems/mainWindow/mainMenu.cpp @@ -0,0 +1,229 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainMenu + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/const.h" +#include "../../../core/mixer.h" +#include "../../../core/conf.h" +#include "../../../core/patch.h" +#include "../../../core/channel.h" +#include "../../../core/sampleChannel.h" +#include "../../../utils/gui.h" +#include "../../../glue/storage.h" +#include "../../../glue/main.h" +#include "../../elems/ge_mixed.h" +#include "../../elems/basics/boxtypes.h" +#include "../../dialogs/gd_mainWindow.h" +#include "../../dialogs/gd_about.h" +#include "../../dialogs/gd_config.h" +#include "../../dialogs/gd_browser.h" +#include "../../dialogs/gd_warnings.h" +#include "../../dialogs/midiIO/midiInputMaster.h" +#include "keyboard/keyboard.h" +#include "mainMenu.h" + + +extern Mixer G_Mixer; +extern Patch G_Patch; +extern Conf G_Conf; +extern gdMainWindow *G_MainWin; + + +geMainMenu::geMainMenu(int x, int y) + : Fl_Group(x, y, 300, 20) +{ + begin(); + + file = new gClick(x, y, 70, 21, "file"); + edit = new gClick(file->x()+file->w()+4, y, 70, 21, "edit"); + config = new gClick(edit->x()+edit->w()+4, y, 70, 21, "config"); + about = new gClick(config->x()+config->w()+4, y, 70, 21, "about"); + + end(); + + resizable(NULL); // don't resize any widget + + about->callback(cb_about, (void*)this); + file->callback(cb_file, (void*)this); + edit->callback(cb_edit, (void*)this); + config->callback(cb_config, (void*)this); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainMenu::cb_about (Fl_Widget *v, void *p) { ((geMainMenu*)p)->__cb_about(); } +void geMainMenu::cb_config(Fl_Widget *v, void *p) { ((geMainMenu*)p)->__cb_config(); } +void geMainMenu::cb_file (Fl_Widget *v, void *p) { ((geMainMenu*)p)->__cb_file(); } +void geMainMenu::cb_edit (Fl_Widget *v, void *p) { ((geMainMenu*)p)->__cb_edit(); } + + +/* -------------------------------------------------------------------------- */ + + +void geMainMenu::__cb_about() +{ + gu_openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainMenu::__cb_config() +{ + gu_openSubWindow(G_MainWin, new gdConfig(380, 370), WID_CONFIG); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainMenu::__cb_file() +{ + /* An Fl_Menu_Button is made of many Fl_Menu_Item */ + + Fl_Menu_Item menu[] = { + {"Open patch or project..."}, + {"Save patch..."}, + {"Save project..."}, + {"Quit Giada"}, + {0} + }; + + Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); + b->box(G_CUSTOM_BORDER_BOX); + b->textsize(GUI_FONT_SIZE_BASE); + b->textcolor(COLOR_TEXT_0); + b->color(COLOR_BG_0); + + const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); + if (!m) return; + + if (strcmp(m->label(), "Open patch or project...") == 0) { + gWindow *childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Load patch or project", + G_Conf.patchPath, glue_loadPatch, NULL); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); + return; + } + if (strcmp(m->label(), "Save patch...") == 0) { + if (G_Mixer.hasLogicalSamples() || G_Mixer.hasEditedSamples()) + if (!gdConfirmWin("Warning", "You should save a project in order to store\nyour takes and/or processed samples.")) + return; + gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Save patch", + G_Conf.patchPath, G_Patch.name, glue_savePatch, NULL); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); + return; + } + if (strcmp(m->label(), "Save project...") == 0) { + gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Save project", + G_Conf.patchPath, G_Patch.name, glue_saveProject, NULL); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); + return; + } + if (strcmp(m->label(), "Quit Giada") == 0) { + G_MainWin->do_callback(); + return; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainMenu::__cb_edit() +{ + Fl_Menu_Item menu[] = { + {"Clear all samples"}, + {"Clear all actions"}, + {"Remove empty columns"}, + {"Reset to init state"}, + {"Setup global MIDI input..."}, + {0} + }; + + /* clear all actions disabled if no recs, clear all samples disabled + * if no samples. */ + + menu[1].deactivate(); + + for (unsigned i=0; ihasActions) { + menu[1].activate(); + break; + } + for (unsigned i=0; itype == CHANNEL_SAMPLE) + if (((SampleChannel*)G_Mixer.channels.at(i))->wave != NULL) { + menu[0].activate(); + break; + } + + Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); + b->box(G_CUSTOM_BORDER_BOX); + b->textsize(GUI_FONT_SIZE_BASE); + b->textcolor(COLOR_TEXT_0); + b->color(COLOR_BG_0); + + const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); + if (!m) return; + + if (strcmp(m->label(), "Clear all samples") == 0) { + if (!gdConfirmWin("Warning", "Clear all samples: are you sure?")) + return; + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); + glue_clearAllSamples(); + return; + } + if (strcmp(m->label(), "Clear all actions") == 0) { + if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) + return; + G_MainWin->delSubWindow(WID_ACTION_EDITOR); + glue_clearAllRecs(); + return; + } + if (strcmp(m->label(), "Reset to init state") == 0) { + if (!gdConfirmWin("Warning", "Reset to init state: are you sure?")) + return; + gu_closeAllSubwindows(); + glue_resetToInitState(); + return; + } + if (strcmp(m->label(), "Remove empty columns") == 0) { + G_MainWin->keyboard->organizeColumns(); + return; + } + if (strcmp(m->label(), "Setup global MIDI input...") == 0) { + gu_openSubWindow(G_MainWin, new gdMidiInputMaster(), 0); + return; + } +} diff --git a/src/gui/elems/mainWindow/mainMenu.h b/src/gui/elems/mainWindow/mainMenu.h new file mode 100644 index 0000000..a8e6f4f --- /dev/null +++ b/src/gui/elems/mainWindow/mainMenu.h @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainMenu + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_MAIN_MENU_H +#define GE_MAIN_MENU_H + + +#include + + +class geMainMenu : public Fl_Group +{ +private: + + class gClick *file; + class gClick *edit; + class gClick *config; + class gClick *about; + + static void cb_about (Fl_Widget *v, void *p); + static void cb_config(Fl_Widget *v, void *p); + static void cb_file (Fl_Widget *v, void *p); + static void cb_edit (Fl_Widget *v, void *p); + + inline void __cb_about (); + inline void __cb_config(); + inline void __cb_file (); + inline void __cb_edit (); + +public: + + geMainMenu(int x, int y); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/mainTimer.cpp b/src/gui/elems/mainWindow/mainTimer.cpp new file mode 100644 index 0000000..e1c0d94 --- /dev/null +++ b/src/gui/elems/mainWindow/mainTimer.cpp @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainTimer + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/const.h" +#include "../../../core/mixer.h" +#include "../../../core/graphics.h" +#include "../../../glue/main.h" +#include "../../../utils/gui.h" +#include "../../elems/ge_mixed.h" +#include "../../dialogs/gd_mainWindow.h" +#include "../../dialogs/gd_bpmInput.h" +#include "../../dialogs/gd_beatsInput.h" +#include "mainTimer.h" + + +extern Mixer G_Mixer; +extern gdMainWindow *G_MainWin; + + +geMainTimer::geMainTimer(int x, int y) + : Fl_Group(x, y, 180, 20) +{ + begin(); + + quantizer = new gChoice(x, y, 40, 20, "", false); + bpm = new gClick (quantizer->x()+quantizer->w()+4, y, 40, 20); + meter = new gClick (bpm->x()+bpm->w()+8, y, 40, 20, "4/1"); + multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm); + divider = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm); + + end(); + + resizable(NULL); // don't resize any widget + + char buf[6]; snprintf(buf, 6, "%f", G_Mixer.bpm); + bpm->copy_label(buf); + + bpm->callback(cb_bpm, (void*)this); + meter->callback(cb_meter, (void*)this); + multiplier->callback(cb_multiplier, (void*)this); + divider->callback(cb_divider, (void*)this); + + quantizer->add("off", 0, cb_quantizer, (void*)this); + quantizer->add("1b", 0, cb_quantizer, (void*)this); + quantizer->add("2b", 0, cb_quantizer, (void*)this); + quantizer->add("3b", 0, cb_quantizer, (void*)this); + quantizer->add("4b", 0, cb_quantizer, (void*)this); + quantizer->add("6b", 0, cb_quantizer, (void*)this); + quantizer->add("8b", 0, cb_quantizer, (void*)this); + quantizer->value(0); // "off" by default +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::cb_bpm (Fl_Widget *v, void *p) { ((geMainTimer*)p)->__cb_bpm(); } +void geMainTimer::cb_meter (Fl_Widget *v, void *p) { ((geMainTimer*)p)->__cb_meter(); } +void geMainTimer::cb_quantizer (Fl_Widget *v, void *p) { ((geMainTimer*)p)->__cb_quantizer(); } +void geMainTimer::cb_multiplier(Fl_Widget *v, void *p) { ((geMainTimer*)p)->__cb_multiplier(); } +void geMainTimer::cb_divider (Fl_Widget *v, void *p) { ((geMainTimer*)p)->__cb_divider(); } + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::__cb_bpm() +{ + gu_openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::__cb_meter() +{ + gu_openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::__cb_quantizer() +{ + glue_quantize(quantizer->value()); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::__cb_multiplier() +{ + glue_beatsMultiply(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::__cb_divider() +{ + glue_beatsDivide(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::setBpm(const char *v) +{ + bpm->copy_label(v); +} + + +void geMainTimer::setBpm(float v) +{ + char buf[6]; + sprintf(buf, "%.01f", v); // only 1 decimal place (e.g. 120.0) + bpm->copy_label(buf); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::setLock(bool v) +{ + if (v) { + bpm->deactivate(); + meter->deactivate(); + multiplier->deactivate(); + divider->deactivate(); + } + else { + bpm->activate(); + meter->activate(); + multiplier->activate(); + divider->activate(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTimer::setMeter(int beats, int bars) +{ + char buf[8]; + sprintf(buf, "%d/%d", beats, bars); + meter->copy_label(buf); +} diff --git a/src/gui/elems/mainWindow/mainTimer.h b/src/gui/elems/mainWindow/mainTimer.h new file mode 100644 index 0000000..8be1d82 --- /dev/null +++ b/src/gui/elems/mainWindow/mainTimer.h @@ -0,0 +1,74 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainTimer + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_MAIN_TIMER_H +#define GE_MAIN_TIMER_H + + +#include + + +class geMainTimer : public Fl_Group +{ +private: + + class gClick *bpm; + class gClick *meter; + class gChoice *quantizer; + class gClick *multiplier; + class gClick *divider; + + static void cb_bpm (Fl_Widget *v, void *p); + static void cb_meter (Fl_Widget *v, void *p); + static void cb_quantizer (Fl_Widget *v, void *p); + static void cb_multiplier(Fl_Widget *v, void *p); + static void cb_divider (Fl_Widget *v, void *p); + + inline void __cb_bpm(); + inline void __cb_meter(); + inline void __cb_quantizer(); + inline void __cb_multiplier(); + inline void __cb_divider(); + +public: + + geMainTimer(int x, int y); + + void setBpm(const char *v); + void setBpm(float v); + void setMeter(int beats, int bars); + + /* setLock + Locks bpm, beter and multipliers. Used during audio recordings. */ + + void setLock(bool v); +}; + + +#endif diff --git a/src/gui/elems/mainWindow/mainTransport.cpp b/src/gui/elems/mainWindow/mainTransport.cpp new file mode 100644 index 0000000..9b54c22 --- /dev/null +++ b/src/gui/elems/mainWindow/mainTransport.cpp @@ -0,0 +1,160 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainTransport + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "../../../core/graphics.h" +#include "../../../glue/main.h" +#include "../../../glue/io.h" +#include "../ge_mixed.h" +#include "mainTransport.h" + + +geMainTransport::geMainTransport(int x, int y) + : Fl_Group(x, y, 131, 25) +{ + begin(); + + rewind = new gClick(x, y, 25, 25, "", rewindOff_xpm, rewindOn_xpm); + play = new gClick(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm); + recAction = new gClick(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm); + recInput = new gClick(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm); + metronome = new gClick(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm); + + end(); + + resizable(NULL); // don't resize any widget + + rewind->callback(cb_rewind, (void*)this); + + play->callback(cb_play); + play->type(FL_TOGGLE_BUTTON); + + recAction->callback(cb_recAction, (void*)this); + recAction->type(FL_TOGGLE_BUTTON); + + recInput->callback(cb_recInput, (void*)this); + recInput->type(FL_TOGGLE_BUTTON); + + metronome->callback(cb_metronome); + metronome->type(FL_TOGGLE_BUTTON); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::cb_rewind (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_rewind(); } +void geMainTransport::cb_play (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_play(); } +void geMainTransport::cb_recAction(Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_recAction(); } +void geMainTransport::cb_recInput (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_recInput(); } +void geMainTransport::cb_metronome(Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_metronome(); } + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::__cb_rewind() +{ + glue_rewindSeq(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::__cb_play() +{ + glue_startStopSeq(true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::__cb_recAction() +{ + glue_startStopActionRec(true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::__cb_recInput() +{ + glue_startStopInputRec(true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::__cb_metronome() +{ + glue_startStopMetronome(true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::updatePlay(int v) +{ + play->value(v); + play->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::updateMetronome(int v) +{ + metronome->value(v); + metronome->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::updateRecInput(int v) +{ + recInput->value(v); + recInput->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMainTransport::updateRecAction(int v) +{ + recAction->value(v); + recAction->redraw(); +} diff --git a/src/gui/elems/mainWindow/mainTransport.h b/src/gui/elems/mainWindow/mainTransport.h new file mode 100644 index 0000000..57b83e3 --- /dev/null +++ b/src/gui/elems/mainWindow/mainTransport.h @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * mainTransport + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_MAIN_TRANSPORT_H +#define GE_MAIN_TRANSPORT_H + + +#include + + +class geMainTransport : public Fl_Group +{ +private: + + class gClick *rewind; + class gClick *play; + class gClick *recAction; + class gClick *recInput; + class gClick *metronome; + + static void cb_rewind (Fl_Widget *v, void *p); + static void cb_play (Fl_Widget *v, void *p); + static void cb_recAction(Fl_Widget *v, void *p); + static void cb_recInput (Fl_Widget *v, void *p); + static void cb_metronome(Fl_Widget *v, void *p); + + inline void __cb_rewind (); + inline void __cb_play (); + inline void __cb_recAction(); + inline void __cb_recInput (); + inline void __cb_metronome(); + +public: + + geMainTransport(int x, int y); + + void updatePlay (int v); + void updateMetronome(int v); + void updateRecInput (int v); + void updateRecAction(int v); +}; + +#endif diff --git a/src/gui/elems/midiChannel.cpp b/src/gui/elems/midiChannel.cpp deleted file mode 100644 index bfdbea5..0000000 --- a/src/gui/elems/midiChannel.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_midiChannel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/mixer.h" -#include "../../core/conf.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/graphics.h" -#include "../../core/channel.h" -#include "../../core/midiChannel.h" -#include "../../glue/channel.h" -#include "../../glue/main.h" -#include "../../glue/io.h" -#include "../../utils/gui.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_keyGrabber.h" -#include "../dialogs/gd_midiInput.h" -#include "../dialogs/gd_editor.h" -#include "../dialogs/gd_actionEditor.h" -#include "../dialogs/gd_warnings.h" -#include "../dialogs/gd_browser.h" -#include "../dialogs/gd_keyGrabber.h" -#include "../dialogs/gd_midiOutput.h" -#include "../dialogs/gd_pluginList.h" -#include "midiChannel.h" - - -extern Mixer G_Mixer; -extern Conf G_Conf; -extern Recorder G_Recorder; -extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *G_MainWin; - - -geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch) - : geChannel(X, Y, W, H, CHANNEL_MIDI, ch) -{ - begin(); - -#if defined(WITH_VST) - int delta = 144; // (6 widgets * 20) + (6 paddings * 4) -#else - int delta = 120; // (5 widgets * 20) + (5 paddings * 4) -#endif - - button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); - arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); - mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --"); - mute = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); - solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); -#if defined(WITH_VST) - fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); - vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); -#else - vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); -#endif - - end(); - - resizable(mainButton); - - update(); - - button->callback(cb_button, (void*)this); - button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease - - arm->type(FL_TOGGLE_BUTTON); - arm->callback(cb_arm, (void*)this); - -#ifdef WITH_VST - fx->callback(cb_openFxWindow, (void*)this); -#endif - - mute->type(FL_TOGGLE_BUTTON); - mute->callback(cb_mute, (void*)this); - - solo->type(FL_TOGGLE_BUTTON); - solo->callback(cb_solo, (void*)this); - - mainButton->callback(cb_openMenu, (void*)this); - - vol->callback(cb_changeVol, (void*)this); - - ch->guiChannel = this; -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::cb_button (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_button(); } -void geMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_openMenu(); } - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::__cb_button() -{ - if (button->value()) - glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::__cb_openMenu() -{ - Fl_Menu_Item rclick_menu[] = { - {"Edit actions..."}, // 0 - {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 1 - {"All"}, // 2 - {0}, // 3 - {"Setup keyboard input..."}, // 5 - {"Setup MIDI input..."}, // 6 - {"Setup MIDI output..."}, // 7 - {"Clone channel"}, // 8 - {"Delete channel"}, // 9 - {0} - }; - - /* no 'clear actions' if there are no actions */ - - if (!ch->hasActions) - rclick_menu[1].deactivate(); - - Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); - b->textsize(GUI_FONT_SIZE_BASE); - b->textcolor(COLOR_TEXT_0); - b->color(COLOR_BG_0); - - const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); - if (!m) return; - - if (strcmp(m->label(), "Delete channel") == 0) { - if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) - return; - glue_deleteChannel(ch); - return; - } - - if (strcmp(m->label(), "Clone channel") == 0) { - glue_cloneChannel(ch); - return; - } - - if (strcmp(m->label(), "Setup keyboard input...") == 0) { - gu_openSubWindow(G_MainWin, new gdKeyGrabber(ch), 0); - //new gdKeyGrabber(ch); - return; - } - - if (strcmp(m->label(), "All") == 0) { - if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) - return; - G_Recorder.clearChan(ch->index); - gu_refreshActionEditor(); // refresh a.editor window, it could be open - return; - } - - if (strcmp(m->label(), "Edit actions...") == 0) { - gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); - return; - } - - if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); - return; - } - - if (strcmp(m->label(), "Setup MIDI output...") == 0) { - //gu_openSubWindow(G_MainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); - gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh((MidiChannel*) ch), 0); - return; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::refresh() -{ - setColorsByStatus(ch->status, ch->recStatus); - mainButton->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::reset() -{ - mainButton->setDefaultMode("-- MIDI --"); - mainButton->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::update() -{ - if (((MidiChannel*) ch)->midiOut) { - char tmp[32]; - sprintf(tmp, "-- MIDI (channel %d) --", ((MidiChannel*) ch)->midiOutChan+1); - mainButton->copy_label(tmp); - } - else - mainButton->label("-- MIDI --"); - - vol->value(ch->volume); - mute->value(ch->mute); - solo->value(ch->solo); - - mainButton->setKey(ch->key); - -#ifdef WITH_VST - fx->full = ch->plugins.size() > 0; - fx->redraw(); -#endif -} - - -/* -------------------------------------------------------------------------- */ - - -void geMidiChannel::resize(int X, int Y, int W, int H) -{ - geChannel::resize(X, Y, W, H); - - arm->hide(); -#ifdef WITH_VST - fx->hide(); -#endif - - if (w() > BREAK_ARM) - arm->show(); -#ifdef WITH_VST - if (w() > BREAK_FX) - fx->show(); -#endif - - packWidgets(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char *l) - : geChannelButton(x, y, w, h, l) {} - - -/* -------------------------------------------------------------------------- */ - - -int geMidiChannelButton::handle(int e) -{ - // MIDI drag-n-drop does nothing so far. - return gClick::handle(e); -} diff --git a/src/gui/elems/midiChannel.h b/src/gui/elems/midiChannel.h deleted file mode 100644 index cd06ddc..0000000 --- a/src/gui/elems/midiChannel.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_midiChannel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_MIDI_CHANNEL_H -#define GE_MIDI_CHANNEL_H - - -#include "channel.h" -#include "channelButton.h" - - -class geMidiChannel : public geChannel -{ -private: - - static void cb_button (Fl_Widget *v, void *p); - static void cb_openMenu (Fl_Widget *v, void *p); - - inline void __cb_button (); - inline void __cb_openMenu (); - inline void __cb_readActions (); - -public: - - geMidiChannel(int x, int y, int w, int h, class MidiChannel *ch); - - void reset (); - void update (); - void refresh (); - int keyPress(int event); // TODO - move to base class - void resize (int x, int y, int w, int h); -}; - - -/* -------------------------------------------------------------------------- */ - - -class geMidiChannelButton : public geChannelButton -{ -public: - geMidiChannelButton(int x, int y, int w, int h, const char *l=0); - int handle(int e); -}; - - -#endif diff --git a/src/gui/elems/midiLearner.cpp b/src/gui/elems/midiLearner.cpp new file mode 100644 index 0000000..f63b208 --- /dev/null +++ b/src/gui/elems/midiLearner.cpp @@ -0,0 +1,110 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiLearner + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "ge_mixed.h" +#include "basics/boxtypes.h" +#include "midiLearner.h" + + +extern KernelMidi G_KernelMidi; + + +geMidiLearner::geMidiLearner(int X, int Y, int W, const char *l, + KernelMidi::cb_midiLearn *cb, uint32_t *param) + : Fl_Group(X, Y, W, 20), + callback(cb), + param (param) +{ + begin(); + text = new gBox(x(), y(), 156, 20, l); + value = new gClick(text->x()+text->w()+4, y(), 80, 20); + button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn"); + end(); + + text->box(G_CUSTOM_BORDER_BOX); + text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); + + value->box(G_CUSTOM_BORDER_BOX); + value->callback(cb_value, (void*)this); + value->when(FL_WHEN_RELEASE); + updateValue(); + + button->type(FL_TOGGLE_BUTTON); + button->callback(cb_button, (void*)this); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiLearner::updateValue() +{ + char buf[16]; + if (*param != 0x0) + snprintf(buf, 9, "0x%X", *param); + else + snprintf(buf, 16, "(not set)"); + value->copy_label(buf); + button->value(0); +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiLearner::cb_button(Fl_Widget *v, void *p) { ((geMidiLearner*)p)->__cb_button(); } +void geMidiLearner::cb_value(Fl_Widget *v, void *p) { ((geMidiLearner*)p)->__cb_value(); } + + +/* -------------------------------------------------------------------------- */ + + +void geMidiLearner::__cb_value() +{ + if (Fl::event_button() == FL_RIGHT_MOUSE) { + *param = 0x0; + updateValue(); + } + /// TODO - elif (LEFT_MOUSE) : insert values by hand +} + + +/* -------------------------------------------------------------------------- */ + + +void geMidiLearner::__cb_button() +{ + if (button->value() == 1) { + cbData.window = (gdMidiInput*) parent(); // parent = gdMidiInput + cbData.learner = this; + G_KernelMidi.startMidiLearn(callback, (void*)&cbData); + } + else + G_KernelMidi.stopMidiLearn(); +} diff --git a/src/gui/elems/midiLearner.h b/src/gui/elems/midiLearner.h new file mode 100644 index 0000000..9d5b0a0 --- /dev/null +++ b/src/gui/elems/midiLearner.h @@ -0,0 +1,84 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiLearner + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_LEARNER_H +#define GE_LEARNER_H + + +#include +#include "../../core/kernelMidi.h" + + +extern KernelMidi G_KernelMidi; + + +class geMidiLearner : public Fl_Group +{ +private: + + /* callback + * cb to pass to kernelMidi. Requires two parameters: + * uint32_t msg - MIDI message + * void *data - extra data */ + + KernelMidi::cb_midiLearn *callback; + + class gBox *text; + class gClick *value; + class gButton *button; + + static void cb_button(Fl_Widget *v, void *p); + static void cb_value (Fl_Widget *v, void *p); + inline void __cb_button(); + inline void __cb_value(); + +public: + + /* cbData_t + * struct we pass to kernelMidi as extra parameter. */ + + struct cbData_t + { + class gdMidiInput *window; + class geMidiLearner *learner; + } cbData; + + /* param + * pointer to ch->midiIn[value] */ + + uint32_t *param; + + geMidiLearner(int x, int y, int w, const char *l, KernelMidi::cb_midiLearn *cb, + uint32_t *param); + + void updateValue(); +}; + + +#endif diff --git a/src/gui/elems/muteEditor.cpp b/src/gui/elems/muteEditor.cpp index e2861b2..1c9ae3b 100644 --- a/src/gui/elems/muteEditor.cpp +++ b/src/gui/elems/muteEditor.cpp @@ -32,7 +32,7 @@ #include "../../utils/log.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" -#include "ge_keyboard.h" +#include "mainWindow/keyboard/keyboard.h" #include "muteEditor.h" @@ -253,6 +253,7 @@ int geMuteEditor::handle(int e) { G_Recorder.rec(pParent->chan->index, ACTION_MUTEON, frame_a); G_Recorder.rec(pParent->chan->index, ACTION_MUTEOFF, frame_b); } + pParent->chan->hasActions = true; G_Recorder.sortActions(); G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow @@ -281,9 +282,13 @@ int geMuteEditor::handle(int e) { //gu_log("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n", // a, b, points.at(a).frame, points.at(b).frame); - G_Recorder.deleteAction(pParent->chan->index, points.at(a).frame, points.at(a).type, false); // false = don't check vals - G_Recorder.deleteAction(pParent->chan->index, points.at(b).frame, points.at(b).type, false); // false = don't check vals - G_Recorder.sortActions(); + G_Recorder.deleteAction(pParent->chan->index, points.at(a).frame, + points.at(a).type, false, &G_Mixer.mutex_recs); // false = don't check vals + G_Recorder.deleteAction(pParent->chan->index, points.at(b).frame, + points.at(b).type, false, &G_Mixer.mutex_recs); // false = don't check vals + pParent->chan->hasActions = G_Recorder.hasActions(pParent->chan->index); + + G_Recorder.sortActions(); G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow extractPoints(); @@ -305,17 +310,17 @@ int geMuteEditor::handle(int e) { int newFrame = points.at(draggedPoint).x * pParent->zoom; - G_Recorder.deleteAction( - pParent->chan->index, - points.at(draggedPoint).frame, - points.at(draggedPoint).type, - false); // don't check values + G_Recorder.deleteAction(pParent->chan->index, + points.at(draggedPoint).frame, points.at(draggedPoint).type, false, + &G_Mixer.mutex_recs); // don't check values + pParent->chan->hasActions = G_Recorder.hasActions(pParent->chan->index); G_Recorder.rec( pParent->chan->index, points.at(draggedPoint).type, newFrame); + pParent->chan->hasActions = true; G_Recorder.sortActions(); points.at(draggedPoint).frame = newFrame; diff --git a/src/gui/elems/pianoItem.cpp b/src/gui/elems/pianoItem.cpp index 870b61a..c6449cb 100644 --- a/src/gui/elems/pianoItem.cpp +++ b/src/gui/elems/pianoItem.cpp @@ -143,6 +143,7 @@ void gePianoItem::record() G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a); G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b); + pParent->chan->hasActions = true; } @@ -151,8 +152,10 @@ void gePianoItem::record() void gePianoItem::remove() { - G_Recorder.deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0); - G_Recorder.deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0); + G_Recorder.deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, + &G_Mixer.mutex_recs, event_a, 0.0); + G_Recorder.deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, + &G_Mixer.mutex_recs, event_b, 0.0); /* send a note-off in case we are deleting it in a middle of a key_on * key_off sequence. */ diff --git a/src/gui/elems/sampleChannel.cpp b/src/gui/elems/sampleChannel.cpp deleted file mode 100644 index 5b7e4c9..0000000 --- a/src/gui/elems/sampleChannel.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_sampleChannel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../../core/pluginHost.h" -#include "../../core/mixer.h" -#include "../../core/conf.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/recorder.h" -#include "../../core/graphics.h" -#include "../../core/wave.h" -#include "../../glue/main.h" -#include "../../glue/io.h" -#include "../../glue/channel.h" -#include "../../glue/storage.h" -#include "../../utils/gui.h" -#include "../../utils/string.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_keyGrabber.h" -#include "../dialogs/gd_midiOutput.h" -#include "../dialogs/gd_midiInput.h" -#include "../dialogs/gd_editor.h" -#include "../dialogs/gd_actionEditor.h" -#include "../dialogs/gd_warnings.h" -#include "../dialogs/gd_browser.h" -#include "ge_status.h" -#include "ge_modeBox.h" -#include "ge_keyboard.h" -#include "sampleChannel.h" - - -extern Mixer G_Mixer; -extern Conf G_Conf; -extern Recorder G_Recorder; -extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *G_MainWin; - - -geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch) - : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch) -{ - begin(); - - button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); - arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); - status = new gStatus(arm->x()+arm->w()+4, y(), 20, 20, ch); - mainButton = new geSampleChannelButton(status->x()+status->w()+4, y(), 20, 20, "-- no sample --"); - readActions = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm); - modeBox = new gModeBox(readActions->x()+readActions->w()+4, y(), 20, 20, ch); - mute = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); - solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); -#ifdef WITH_VST - fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); - vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); -#else - vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); -#endif - - end(); - - resizable(mainButton); - - update(); - - button->callback(cb_button, (void*)this); - button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease - - arm->type(FL_TOGGLE_BUTTON); - arm->callback(cb_arm, (void*)this); - -#ifdef WITH_VST - fx->callback(cb_openFxWindow, (void*)this); -#endif - - mute->type(FL_TOGGLE_BUTTON); - mute->callback(cb_mute, (void*)this); - - solo->type(FL_TOGGLE_BUTTON); - solo->callback(cb_solo, (void*)this); - - mainButton->callback(cb_openMenu, (void*)this); - - readActions->type(FL_TOGGLE_BUTTON); - readActions->value(ch->readActions); - readActions->callback(cb_readActions, (void*)this); - - vol->callback(cb_changeVol, (void*)this); - - ch->guiChannel = this; -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::cb_button (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); } -void geSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); } -void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); } - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::__cb_button() -{ - if (button->value()) // pushed - glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); - else // released - glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift()); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::__cb_openMenu() -{ - /* If you're recording (input or actions) no menu is allowed; you can't do - anything, especially deallocate the channel */ - - if (G_Mixer.recording || G_Recorder.active) - return; - - /* the following is a trash workaround for a FLTK menu. We need a gMenu - * widget asap */ - - Fl_Menu_Item rclick_menu[] = { - {"Load new sample..."}, // 0 - {"Export sample to file..."}, // 1 - {"Setup keyboard input..."}, // 2 - {"Setup MIDI input..."}, // 3 - {"Setup MIDI output..."}, // 4 - {"Edit sample..."}, // 5 - {"Edit actions..."}, // 6 - {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 7 - {"All"}, // 8 - {"Mute"}, // 9 - {"Volume"}, // 10 - {"Start/Stop"}, // 11 - {0}, // 12 - {"Clone channel"}, // 13 - {"Free channel"}, // 14 - {"Delete channel"}, // 15 - {0} - }; - - if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) { - rclick_menu[1].deactivate(); - rclick_menu[5].deactivate(); - rclick_menu[14].deactivate(); - } - - /* no 'clear actions' if there are no actions */ - - if (!ch->hasActions) - rclick_menu[7].deactivate(); - - /* no 'clear start/stop actions' for those channels in loop mode: - * they cannot have start/stop actions. */ - - if (((SampleChannel*)ch)->mode & LOOP_ANY) - rclick_menu[11].deactivate(); - - Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); - b->box(G_BOX); - b->textsize(GUI_FONT_SIZE_BASE); - b->textcolor(COLOR_TEXT_0); - b->color(COLOR_BG_0); - - const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); - if (!m) return; - - if (strcmp(m->label(), "Load new sample...") == 0) { - openBrowser(BROWSER_LOAD_SAMPLE); - return; - } - - if (strcmp(m->label(), "Setup keyboard input...") == 0) { - new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow - return; - } - - if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); - return; - } - - if (strcmp(m->label(), "Setup MIDI output...") == 0) { - gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh((SampleChannel*) ch), 0); - return; - } - - if (strcmp(m->label(), "Edit sample...") == 0) { - gu_openSubWindow(G_MainWin, new gdEditor((SampleChannel*) ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor - return; - } - - if (strcmp(m->label(), "Export sample to file...") == 0) { - openBrowser(BROWSER_SAVE_SAMPLE); - return; - } - - if (strcmp(m->label(), "Delete channel") == 0) { - if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) - return; - glue_deleteChannel(ch); - return; - } - - if (strcmp(m->label(), "Free channel") == 0) { - if (ch->status == STATUS_PLAY) { - if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?")) - return; - } - else if (!gdConfirmWin("Warning", "Free channel: are you sure?")) - return; - - glue_freeChannel(ch); - - /* delete any related subwindow */ - - /** FIXME - use gu_closeAllSubwindows() */ - - G_MainWin->delSubWindow(WID_FILE_BROWSER); - G_MainWin->delSubWindow(WID_ACTION_EDITOR); - G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); - G_MainWin->delSubWindow(WID_FX_LIST); - - return; - } - - if (strcmp(m->label(), "Clone channel") == 0) { - glue_cloneChannel(ch); - return; - } - - if (strcmp(m->label(), "Mute") == 0) { - if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?")) - return; - G_Recorder.clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF); - if (!ch->hasActions) - hideActionButton(); - - /* TODO - set mute=false */ - - gu_refreshActionEditor(); // refresh a.editor window, it could be open - return; - } - - if (strcmp(m->label(), "Start/Stop") == 0) { - if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?")) - return; - G_Recorder.clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN); - if (!ch->hasActions) - hideActionButton(); - gu_refreshActionEditor(); // refresh a.editor window, it could be open - return; - } - - if (strcmp(m->label(), "Volume") == 0) { - if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?")) - return; - G_Recorder.clearAction(ch->index, ACTION_VOLUME); - if (!ch->hasActions) - hideActionButton(); - gu_refreshActionEditor(); // refresh a.editor window, it could be open - return; - } - - if (strcmp(m->label(), "All") == 0) { - if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) - return; - G_Recorder.clearChan(ch->index); - hideActionButton(); - gu_refreshActionEditor(); // refresh a.editor window, it could be open - return; - } - - if (strcmp(m->label(), "Edit actions...") == 0) { - gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); - return; - } -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::__cb_readActions() -{ - glue_startStopReadingRecs((SampleChannel*) ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::openBrowser(int type) -{ - gWindow *childWin = NULL; - switch (type) { - case BROWSER_LOAD_SAMPLE: - childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, - G_Conf.browserW, G_Conf.browserH, "Browse sample", - G_Conf.samplePath.c_str(), glue_loadSample, ch); - break; - case BROWSER_SAVE_SAMPLE: - childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, - G_Conf.browserW, G_Conf.browserH, "Save sample", \ - G_Conf.samplePath.c_str(), "", glue_saveSample, ch); - break; - } - if (childWin) - gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::refresh() -{ - if (!mainButton->visible()) // mainButton invisible? status too (see below) - return; - - setColorsByStatus(ch->status, ch->recStatus); - - if (((SampleChannel*) ch)->wave != NULL) { - if (G_Mixer.recording && ch->armed) - mainButton->setInputRecordMode(); - if (G_Recorder.active) { - if (G_Recorder.canRec(ch)) - mainButton->setActionRecordMode(); - } - status->redraw(); // status invisible? sampleButton too (see below) - } - mainButton->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::reset() -{ - hideActionButton(); - mainButton->setDefaultMode("-- no sample --"); - mainButton->redraw(); - status->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::update() -{ - /* update sample button's label */ - - switch (ch->status) { - case STATUS_EMPTY: - mainButton->label("-- no sample --"); - break; - case STATUS_MISSING: - case STATUS_WRONG: - mainButton->label("* file not found! *"); - break; - default: - mainButton->label(((SampleChannel*) ch)->wave->name.c_str()); - break; - } - - /* update channels. If you load a patch with recorded actions, the 'R' - * button must be shown. Moreover if the actions are active, the 'R' - * button must be activated accordingly. */ - - if (ch->hasActions) - showActionButton(); - else - hideActionButton(); - - /* updates modebox */ - - modeBox->value(((SampleChannel*) ch)->mode); - modeBox->redraw(); - - /* update volumes+mute+solo */ - - vol->value(ch->volume); - mute->value(ch->mute); - solo->value(ch->solo); - - mainButton->setKey(ch->key); - -#ifdef WITH_VST - fx->full = ch->plugins.size() > 0; - fx->redraw(); -#endif -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::showActionButton() -{ - readActions->value(((SampleChannel*) ch)->readActions); - readActions->show(); - packWidgets(); - redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::hideActionButton() -{ - readActions->hide(); - packWidgets(); - redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void geSampleChannel::resize(int X, int Y, int W, int H) -{ - geChannel::resize(X, Y, W, H); - - arm->hide(); - modeBox->hide(); - readActions->hide(); -#ifdef WITH_VST - fx->hide(); -#endif - - if (w() > BREAK_ARM) - arm->show(); -#ifdef WITH_VST - if (w() > BREAK_FX) - fx->show(); -#endif - if (w() > BREAK_MODE_BOX) - modeBox->show(); - if (w() > BREAK_READ_ACTIONS && ch->hasActions) - readActions->show(); - - packWidgets(); -} - - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - - -geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const char *l) - : geChannelButton(x, y, w, h, l) {} - - -/* -------------------------------------------------------------------------- */ - - -int geSampleChannelButton::handle(int e) -{ - int ret = gClick::handle(e); - switch (e) { - case FL_DND_ENTER: - case FL_DND_DRAG: - case FL_DND_RELEASE: { - ret = 1; - break; - } - case FL_PASTE: { - geSampleChannel *gch = (geSampleChannel*) parent(); // parent is geSampleChannel - SampleChannel *ch = (SampleChannel*) gch->ch; - int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str()); - if (result != SAMPLE_LOADED_OK) - G_MainWin->keyboard->printChannelMessage(result); - ret = 1; - break; - } - } - return ret; -} diff --git a/src/gui/elems/sampleChannel.h b/src/gui/elems/sampleChannel.h deleted file mode 100644 index efde2a6..0000000 --- a/src/gui/elems/sampleChannel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_sampleChannel - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#ifndef GE_SAMPLE_CHANNEL_H -#define GE_SAMPLE_CHANNEL_H - - -#include "channel.h" -#include "channelButton.h" - - -class geSampleChannel : public geChannel -{ -private: - - static void cb_button (Fl_Widget *v, void *p); - static void cb_openMenu (Fl_Widget *v, void *p); - static void cb_readActions (Fl_Widget *v, void *p); - - inline void __cb_button (); - inline void __cb_openMenu (); - inline void __cb_readActions (); - - void openBrowser(int type); - -public: - - geSampleChannel(int x, int y, int w, int h, class SampleChannel *ch); - - void reset (); - void update (); - void refresh (); - void resize (int x, int y, int w, int h); - - /* show/hideActionButton - Adds or removes 'R' button when actions are available. */ - - void showActionButton(); - void hideActionButton(); - - class gModeBox *modeBox; - class gClick *readActions; -}; - - -/* -------------------------------------------------------------------------- */ - - -class geSampleChannelButton : public geChannelButton -{ -public: - geSampleChannelButton(int x, int y, int w, int h, const char *l=0); - int handle(int e); -}; - - -#endif diff --git a/src/utils/gui.cpp b/src/utils/gui.cpp index 5daf5d5..715126d 100644 --- a/src/utils/gui.cpp +++ b/src/utils/gui.cpp @@ -38,9 +38,13 @@ #include "../gui/dialogs/gd_warnings.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_actionEditor.h" -#include "../gui/elems/ge_keyboard.h" #include "../gui/elems/ge_window.h" -#include "../gui/elems/channel.h" +#include "../gui/elems/mainWindow/mainIO.h" +#include "../gui/elems/mainWindow/mainTimer.h" +#include "../gui/elems/mainWindow/mainTransport.h" +#include "../gui/elems/mainWindow/beatMeter.h" +#include "../gui/elems/mainWindow/keyboard/keyboard.h" +#include "../gui/elems/mainWindow/keyboard/channel.h" #include "log.h" #include "string.h" #include "gui.h" @@ -68,7 +72,7 @@ void gu_refreshUI() /* update dynamic elements: in and out meters, beat meter and * each channel */ - G_MainWin->inOut->refresh(); + G_MainWin->mainIO->refresh(); G_MainWin->beatMeter->redraw(); G_MainWin->keyboard->refreshColumns(); @@ -102,18 +106,18 @@ void gu_updateControls() for (unsigned i=0; iguiChannel->update(); - G_MainWin->inOut->setOutVol(G_Mixer.outVol); - G_MainWin->inOut->setInVol(G_Mixer.inVol); + G_MainWin->mainIO->setOutVol(G_Mixer.outVol); + G_MainWin->mainIO->setInVol(G_Mixer.inVol); #ifdef WITH_VST - G_MainWin->inOut->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0); - G_MainWin->inOut->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0); + G_MainWin->mainIO->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0); + G_MainWin->mainIO->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0); #endif - G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); - G_MainWin->timing->setBpm(G_Mixer.bpm); + G_MainWin->mainTimer->setMeter(G_Mixer.beats, G_Mixer.bars); + G_MainWin->mainTimer->setBpm(G_Mixer.bpm); - G_MainWin->controller->updatePlay(G_Mixer.running); - G_MainWin->controller->updateMetronome(G_Mixer.metronome); + G_MainWin->mainTransport->updatePlay(G_Mixer.running); + G_MainWin->mainTransport->updateMetronome(G_Mixer.metronome); }