From: Jaromír Mikeš Date: Thu, 1 Sep 2016 23:34:23 +0000 (+0200) Subject: New upstream version 0.13.0~dfsg1 X-Git-Tag: archive/raspbian/0.15.4+ds1-1+rpi1^2~12^2~14 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=67b8c7fa2b57f2f5ad08d1ba136c6c66227389c5;p=giada.git New upstream version 0.13.0~dfsg1 --- diff --git a/.travis.yml b/.travis.yml index 8ea13bf..5c770bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,10 +14,12 @@ notifications: 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 libsndfile1-dev libsamplerate0-dev libfltk1.3-dev libasound2-dev libxpm-dev libpulse-dev libjack-dev libxrandr-dev libx11-dev libxinerama-dev libxcursor-dev + - 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 @@ -34,10 +36,6 @@ before_script: - sudo ldconfig - cd .. - # Download wav file for testing purposes - - - wget http://download.wavetlan.com/SVV/Media/HTTP/WAV/Media-Convert/Media-Convert_test3_PCM_Stereo_VBR_16SS_11025Hz.wav -O test.wav - # Download midimaps package for testing purposes - wget https://github.com/monocasual/giada-midimaps/archive/master.zip -O giada-midimaps-master.zip @@ -47,9 +45,9 @@ before_script: # Download vst plugin for testing purposes - - wget 'http://downloads.sourceforge.net/project/distrho/2014-08-26/dexed-linux64bit-fixed.tar.xz?r=http%3A%2F%2Fdistrho.sourceforge.net%2Fports&ts=1454876566&use_mirror=freefr' -O dexed.tar.xz - - tar xf dexed.tar.xz dexed-linux64bit/Dexed.so - - cp dexed-linux64bit/Dexed.so . + - 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. diff --git a/ChangeLog b/ChangeLog index c39f012..abcbc3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,24 @@ -------------------------------------------------------------------------------- +0.13.0 --- +- Deep file browser refactoring +- Save browser's scroll position and last item selected on opening +- Load patches/projects/samples on double click +- 64 bit builds for Windows +- Prevent deprecated patch from crashing if a plugin is not found in the stack +- Force logger to flush to file on Windows +- Add more default values for windows' dimensions and positions +- Avoid crashes on Configuration panel if no midimaps were selected +- Fix missing keyRelease actions in action editor +- Update JUCE to version 4.2.3 +- Don't include JUCE on tests without VST support (GitHub #75) +- Fix compilation errors on GCC 6 (GitHub #82) +- Fix wrong channel's actions count that prevented "R" button to be toggled + properly +- Fixed a bug that prevented actions on frame 0 to being properly reproduced + + 0.12.2 --- 2016 . 06 . 02 - Update RtAudio to version 4.1.2 - Add WASAPI support on Windows diff --git a/Makefile.am b/Makefile.am index 5d43fcd..a78f094 100644 --- a/Makefile.am +++ b/Makefile.am @@ -135,7 +135,9 @@ src/utils/gui_utils.h \ src/utils/gui_utils.cpp \ src/utils/gvector.h \ src/utils/utils.h \ -src/utils/utils.cpp +src/utils/utils.cpp \ +src/utils/string.h \ +src/utils/string.cpp if WITH_VST giada_SOURCES += \ @@ -164,8 +166,17 @@ giada_CPPFLAGS = # if WITH_VST -giada_CPPFLAGS += -I./src/deps/juce -I./src/deps/vst -I/usr/include \ - -I/usr/include/freetype2 +giada_CPPFLAGS += \ + -I./src/deps/juce \ + -I./src/deps/vst \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 \ + -DJUCE_STANDALONE_APPLICATION=1 \ + -DJUCE_PLUGINHOST_VST=1 \ + -DJUCE_PLUGINHOST_VST3=0 \ + -DJUCE_PLUGINHOST_AU=0 +giada_CXXFLAGS += -Wno-error=misleading-indentation endif if LINUX @@ -182,7 +193,7 @@ if WINDOWS giada_LDADD = -lrtaudio -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \ -lshell32 -lvfw32 -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 -lsndfile \ -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser -lpthreadGC2 -ljansson \ - -limm32 -lglu32 -lshell32 -lversion -lopengl32 -loleaut32 -lshlwapi + -limm32 -lglu32 -lshell32 -lversion -lopengl32 -loleaut32 -lshlwapi -lcomdlg32 giada_LDFLAGS = -mwindows -static giada_SOURCES += resource.rc endif @@ -227,7 +238,10 @@ src/core/pluginHost.cpp \ src/core/dataStorageIni.cpp \ src/core/dataStorageJson.cpp \ src/utils/utils.cpp \ -src/utils/log.cpp \ +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 \ @@ -236,6 +250,7 @@ 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 +endif giada_tests_LDADD = -ljansson -lsndfile -lsamplerate -lfltk -lXext -lX11 -lXft \ -lXpm -lm -ljack -lasound -lpthread -ldl -lpulse-simple -lpulse -lrtmidi \ @@ -243,8 +258,18 @@ giada_tests_LDADD = -ljansson -lsndfile -lsamplerate -lfltk -lXext -lX11 -lXft \ giada_tests_CXXFLAGS = -std=c++11 -giada_tests_CPPFLAGS = -I./src/deps/juce -I./src/deps/vst -I/usr/include \ - -I/usr/include/freetype2 +if WITH_VST +giada_tests_CPPFLAGS = \ + -I./src/deps/juce \ + -I./src/deps/vst \ + -I/usr/include \ + -I/usr/include/freetype2 \ + -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 \ + -DJUCE_STANDALONE_APPLICATION=1 \ + -DJUCE_PLUGINHOST_VST=1 \ + -DJUCE_PLUGINHOST_VST3=0 \ + -DJUCE_PLUGINHOST_AU=0 +endif # make rename ------------------------------------------------------------------ diff --git a/configure.ac b/configure.ac index 8257cf4..16fd0c3 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ # prereq & init AC_PREREQ(2.60) -AC_INIT([giada], [0.12], [giadaloopmachine@gmail.com]) +AC_INIT([giada], [0.13], [giadaloopmachine@gmail.com]) AC_CONFIG_SRCDIR([src/main.cpp]) AM_INIT_AUTOMAKE([subdir-objects]) @@ -60,7 +60,7 @@ AC_ARG_ENABLE( # test if files needed for Travis CI are present. If so, define a new macro # RUN_TESTS_WITH_LOCAL_FILES used during the test suite -if test -f "./test.wav" && test -f "giada-midimaps-master.zip" && test -f "dexed.tar.xz" ; then +if test -f "giada-midimaps-master.zip" && test -f "dexed.tar.xz" ; then AC_DEFINE(RUN_TESTS_WITH_LOCAL_FILES) fi diff --git a/src/core/channel.h b/src/core/channel.h index 201c6a4..e0ee899 100644 --- a/src/core/channel.h +++ b/src/core/channel.h @@ -38,15 +38,7 @@ #include "recorder.h" #ifdef WITH_VST -// TODO - can we move this stuff to a separate file? -#include "../deps/juce/juce_audio_basics/juce_audio_basics.h" -#include "../deps/juce/juce_audio_processors/juce_audio_processors.h" -#include "../deps/juce/juce_core/juce_core.h" -#include "../deps/juce/juce_data_structures/juce_data_structures.h" -#include "../deps/juce/juce_events/juce_events.h" -#include "../deps/juce/juce_graphics/juce_graphics.h" -#include "../deps/juce/juce_gui_basics/juce_gui_basics.h" -#include "../deps/juce/juce_gui_extra/juce_gui_extra.h" + #include "../deps/juce/config.h" #endif using std::vector; diff --git a/src/core/conf.cpp b/src/core/conf.cpp index 8475a8a..eadbce2 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -44,8 +44,8 @@ Conf::Conf() #if defined(__linux__) || defined(__APPLE__) - confFilePath = gGetHomePath() + gGetSlash() + CONF_FILENAME; - confDirPath = gGetHomePath() + gGetSlash(); + confFilePath = gGetHomePath() + G_SLASH + CONF_FILENAME; + confDirPath = gGetHomePath() + G_SLASH; #elif defined(_WIN32) @@ -102,12 +102,12 @@ void Conf::init() limitOutput = false; rsmpQuality = 0; - midiPortIn = DEFAULT_MIDI_PORT_IN; - noNoteOff = false; - midiMapPath = ""; - midiPortOut = DEFAULT_MIDI_PORT_OUT; - midiSync = MIDI_SYNC_NONE; - midiTCfps = 25.0f; + midiPortIn = DEFAULT_MIDI_PORT_IN; + noNoteOff = false; + midiMapPath = ""; + midiPortOut = DEFAULT_MIDI_PORT_OUT; + midiSync = MIDI_SYNC_NONE; + midiTCfps = 25.0f; midiInRewind = 0x0; midiInStartStop = 0x0; @@ -129,24 +129,40 @@ void Conf::init() resizeRecordings = true; - actionEditorZoom = 100; - actionEditorGridOn = false; - actionEditorGridVal = 1; - mainWindowX = 0; mainWindowY = 0; mainWindowW = GUI_WIDTH; mainWindowH = GUI_HEIGHT; + browserX = 0; + browserY = 0; + browserW = 640; + browserH = 480; + browserPosition = 0; + browserLastValue = 0; + + actionEditorX = 0; + actionEditorY = 0; + actionEditorW = 640; + actionEditorH = 480; + actionEditorZoom = 100; + actionEditorGridOn = false; + actionEditorGridVal = 1; + + sampleEditorX = 0; + sampleEditorY = 0; + sampleEditorW = 640; + sampleEditorH = 480; + pianoRollY = -1; pianoRollH = 422; #ifdef WITH_VST - pluginChooserX = 0; - pluginChooserY = 0; - pluginChooserW = 640; - pluginChooserH = 480; + pluginChooserX = 0; + pluginChooserY = 0; + pluginChooserW = 640; + pluginChooserH = 480; pluginSortMethod = 0; #endif @@ -216,6 +232,9 @@ int Conf::read() if (!setInt(jRoot, CONF_KEY_BROWSER_Y, browserY)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_W, browserW)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_H, browserH)) return 0; + if (!setInt(jRoot, CONF_KEY_BROWSER_POSITION, browserPosition)) return 0; + if (!setString(jRoot, CONF_KEY_BROWSER_LAST_PATH, browserLastPath)) return 0; + if (!setInt(jRoot, CONF_KEY_BROWSER_LAST_VALUE, browserLastValue)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_X, actionEditorX)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_Y, actionEditorY)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_W, actionEditorW)) return 0; @@ -314,6 +333,9 @@ int Conf::write() json_object_set_new(jRoot, CONF_KEY_BROWSER_Y, json_integer(browserY)); json_object_set_new(jRoot, CONF_KEY_BROWSER_W, json_integer(browserW)); json_object_set_new(jRoot, CONF_KEY_BROWSER_H, json_integer(browserH)); + json_object_set_new(jRoot, CONF_KEY_BROWSER_POSITION, json_integer(browserPosition)); + json_object_set_new(jRoot, CONF_KEY_BROWSER_LAST_PATH, json_string(browserLastPath.c_str())); + json_object_set_new(jRoot, CONF_KEY_BROWSER_LAST_VALUE, json_integer(browserLastValue)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_X, json_integer(actionEditorX)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_Y, json_integer(actionEditorY)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_W, json_integer(actionEditorW)); diff --git a/src/core/conf.h b/src/core/conf.h index 095440c..f96265d 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -109,13 +109,18 @@ public: string samplePath; int mainWindowX, mainWindowY, mainWindowW, mainWindowH; - int browserX, browserY, browserW, browserH; + + int browserX, browserY, browserW, browserH, browserPosition, browserLastValue; + string browserLastPath; + int actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom; int actionEditorGridVal; int actionEditorGridOn; + int sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH; int sampleEditorGridVal; int sampleEditorGridOn; + int pianoRollY, pianoRollH; int pluginListX, pluginListY; int configX, configY; diff --git a/src/core/const.h b/src/core/const.h index c6e1101..90b362f 100644 --- a/src/core/const.h +++ b/src/core/const.h @@ -32,16 +32,24 @@ /* -- version --------------------------------------------------------------- */ -#define G_VERSION_STR "0.12.2" +#define G_VERSION_STR "0.13.0" #define G_APP_NAME "Giada" #define G_VERSION_MAJOR 0 -#define G_VERSION_MINOR 12 -#define G_VERSION_PATCH 2 +#define G_VERSION_MINOR 13 +#define G_VERSION_PATCH 0 #define CONF_FILENAME "giada.conf" #ifndef BUILD_DATE -# define BUILD_DATE __DATE__ + #define BUILD_DATE __DATE__ +#endif + +#ifdef _WIN32 + #define G_SLASH '\\' + #define G_SLASH_STR "\\" +#else + #define G_SLASH '/' + #define G_SLASH_STR "/" #endif @@ -420,6 +428,9 @@ const int MIDI_CHANS[16] = { #define CONF_KEY_BROWSER_Y "browser_y" #define CONF_KEY_BROWSER_W "browser_w" #define CONF_KEY_BROWSER_H "browser_h" +#define CONF_KEY_BROWSER_POSITION "browser_position" +#define CONF_KEY_BROWSER_LAST_PATH "browser_last_path" +#define CONF_KEY_BROWSER_LAST_VALUE "browser_last_value" #define CONF_KEY_ACTION_EDITOR_X "action_editor_x" #define CONF_KEY_ACTION_EDITOR_Y "action_editor_y" #define CONF_KEY_ACTION_EDITOR_W "action_editor_w" diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h index e0f50b4..011ae2f 100644 --- a/src/core/midiChannel.h +++ b/src/core/midiChannel.h @@ -32,15 +32,7 @@ #ifdef WITH_VST -// TODO - can we move this stuff to a separate file? -#include "../deps/juce/juce_audio_basics/juce_audio_basics.h" -#include "../deps/juce/juce_audio_processors/juce_audio_processors.h" -#include "../deps/juce/juce_core/juce_core.h" -#include "../deps/juce/juce_data_structures/juce_data_structures.h" -#include "../deps/juce/juce_events/juce_events.h" -#include "../deps/juce/juce_graphics/juce_graphics.h" -#include "../deps/juce/juce_gui_basics/juce_gui_basics.h" -#include "../deps/juce/juce_gui_extra/juce_gui_extra.h" + #include "../deps/juce/config.h" #endif #include "channel.h" diff --git a/src/core/midiMapConf.cpp b/src/core/midiMapConf.cpp index bba90bd..41d3706 100644 --- a/src/core/midiMapConf.cpp +++ b/src/core/midiMapConf.cpp @@ -46,7 +46,7 @@ using std::vector; void MidiMapConf::init() { - midimapsPath = gGetHomePath() + gGetSlash() + "midimaps" + gGetSlash(); + midimapsPath = gGetHomePath() + G_SLASH + "midimaps" + G_SLASH; /* scan dir of midi maps and load the filenames into <>maps. */ diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp index 5d3867b..f965e02 100644 --- a/src/core/mixerHandler.cpp +++ b/src/core/mixerHandler.cpp @@ -131,7 +131,8 @@ void mh_loadPatch_DEPR_(bool isProject, const char *projPath) int numChans = G_Patch_DEPR_.getNumChans(); for (int i=0; ireadPatch_DEPR_(samplePath.c_str(), i, &G_Patch_DEPR_, G_Conf.samplerate, G_Conf.rsmpQuality); } diff --git a/src/core/patch_DEPR_.cpp b/src/core/patch_DEPR_.cpp index e25874e..7c30284 100644 --- a/src/core/patch_DEPR_.cpp +++ b/src/core/patch_DEPR_.cpp @@ -552,11 +552,13 @@ int Patch_DEPR_::readPlugins() int nparam = atoi(getValue(tmp).c_str()); Plugin *pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch); sprintf(tmp, "chan%d_p%dbypass", ch->index, j); - pPlugin->setBypass(atoi(getValue(tmp).c_str())); - for (int k=0; kindex, j, k); - float pval = atof(getValue(tmp).c_str()); - pPlugin->setParameter(k, pval); + if (pPlugin) { + pPlugin->setBypass(atoi(getValue(tmp).c_str())); + for (int k=0; kindex, j, k); + float pval = atof(getValue(tmp).c_str()); + pPlugin->setParameter(k, pval); + } } globalOut &= 1; } diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index 61f8261..740bb70 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -41,17 +41,24 @@ int Plugin::idGenerator = 1; /* -------------------------------------------------------------------------- */ -void Plugin::initEditor() +void Plugin::init() { + ui = NULL; + id = idGenerator++;; + bypass = false; + status = 1; + if (getActiveEditor() != NULL) { - gLog("[Plugin::initEditor] plugin has an already active editor!\n"); + gLog("[Plugin::init] plugin has an already active editor!\n"); return; } - ui = createEditor(); + ui = createEditorIfNeeded(); if (ui == NULL) { - gLog("[Plugin::initEditor] unable to create editor!\n"); + gLog("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n"); return; } + + gLog("[Plugin::init] editor initialized and ready\n"); } @@ -65,7 +72,6 @@ void Plugin::showEditor(void *parent) return; } ui->setOpaque(true); - ui->setVisible(true); ui->addToDesktop(0, parent); } @@ -75,7 +81,7 @@ void Plugin::showEditor(void *parent) bool Plugin::isEditorOpen() { - return ui->isVisible(); + return ui->isVisible() && ui->isOnDesktop(); } @@ -95,7 +101,6 @@ void Plugin::closeEditor() { if (ui == NULL) return; - ui->setVisible(false); if (ui->isOnDesktop()) ui->removeFromDesktop(); } diff --git a/src/core/plugin.h b/src/core/plugin.h index 30b79e6..38e411c 100644 --- a/src/core/plugin.h +++ b/src/core/plugin.h @@ -32,14 +32,7 @@ #define __PLUGIN_H__ -#include "../deps/juce/juce_audio_basics/juce_audio_basics.h" -#include "../deps/juce/juce_audio_processors/juce_audio_processors.h" -#include "../deps/juce/juce_core/juce_core.h" -#include "../deps/juce/juce_data_structures/juce_data_structures.h" -#include "../deps/juce/juce_events/juce_events.h" -#include "../deps/juce/juce_graphics/juce_graphics.h" -#include "../deps/juce/juce_gui_basics/juce_gui_basics.h" -#include "../deps/juce/juce_gui_extra/juce_gui_extra.h" +#include "../deps/juce/config.h" using std::string; @@ -58,11 +51,7 @@ private: public: - /* initEditor - * Prepare plugin GUI. 'parent' is a void pointer to the parent window that - * will contain it. */ - - void initEditor(); + void init(); void showEditor(void *parent); @@ -80,17 +69,14 @@ public: string getUniqueId(); - inline void setId() { id = idGenerator++; } - inline int getId() { return id; } - inline bool getStatus() { return status; } - inline bool isBypassed() { return bypass; } - inline int getEditorW() { return ui->getWidth(); } - inline int getEditorH() { return ui->getHeight(); } - - inline void toggleBypass() { bypass = !bypass; } - inline void setStatus(int s) { status = s; } - inline void setBypass(bool b) { bypass = b; } - + 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; } }; #endif diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp index 0f7b60b..9f31f2e 100644 --- a/src/core/pluginHost.cpp +++ b/src/core/pluginHost.cpp @@ -62,7 +62,7 @@ void PluginHost::init(int _buffersize, int _samplerate) buffersize = _buffersize; missingPlugins = false; //unknownPluginList.empty(); - loadList(gGetHomePath() + gGetSlash() + "plugins.xml"); + loadList(gGetHomePath() + G_SLASH + "plugins.xml"); } @@ -151,8 +151,10 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, return NULL; } - p->setStatus(1); - p->setId(); + //p->setStatus(1); + //p->setId(); + //p->initEditor(); + p->init(); p->prepareToPlay(samplerate, buffersize); gLog("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str()); diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h index feb7f38..ac741e2 100644 --- a/src/core/pluginHost.h +++ b/src/core/pluginHost.h @@ -33,16 +33,7 @@ #include -//#include "../deps/juce/AppConfig.h" -// TODO - can we move this stuff to a separate file? -#include "../deps/juce/juce_audio_basics/juce_audio_basics.h" -#include "../deps/juce/juce_audio_processors/juce_audio_processors.h" -#include "../deps/juce/juce_core/juce_core.h" -#include "../deps/juce/juce_data_structures/juce_data_structures.h" -#include "../deps/juce/juce_events/juce_events.h" -#include "../deps/juce/juce_graphics/juce_graphics.h" -#include "../deps/juce/juce_gui_basics/juce_gui_basics.h" -#include "../deps/juce/juce_gui_extra/juce_gui_extra.h" +#include "../deps/juce/config.h" using std::string; diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index 87a4791..53864b0 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -1,11 +1,11 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * recorder * Action recorder. * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -25,7 +25,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -43,8 +43,6 @@ #include "../utils/utils.h" - - extern Mixer G_Mixer; extern Patch_DEPR_ f_patch; extern Conf G_Conf; @@ -62,7 +60,7 @@ bool sortedActions = false; composite cmp; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void init() @@ -73,7 +71,7 @@ void init() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ bool canRec(Channel *ch) @@ -90,7 +88,7 @@ bool canRec(Channel *ch) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void rec(int index, int type, int frame, uint32_t iValue, float fValue) @@ -162,7 +160,7 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void clearChan(int index) @@ -175,12 +173,6 @@ void clearChan(int index) if (j == global.at(i).size()) break; // for each action j of frame i action *a = global.at(i).at(j); if (a->chan == index) { -#ifdef WITH_VST -#if 0 - if (a->type == ACTION_MIDI) - free(a->event); -#endif -#endif free(a); global.at(i).erase(global.at(i).begin() + j); } @@ -196,7 +188,7 @@ void clearChan(int index) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void clearAction(int index, char act) @@ -217,14 +209,14 @@ void clearAction(int index, char act) } } Channel *ch = G_Mixer.getChannelByIndex(index); - ch->hasActions = false; /// FIXME - why this? Isn't it useless if we call chanHasActions? + ch->hasActions = false; /// FIXME - why this? Isn't it useless if we call setChanHasActionsStatus? optimize(); - chanHasActions(index); /// FIXME + setChanHasActionsStatus(index); /// FIXME //print(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue, float fValue) @@ -256,12 +248,6 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa while (lockStatus == 0) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs); if (lockStatus == 0) { -#ifdef WITH_VST -#if 0 - if (type == ACTION_MIDI) - free(a->event); -#endif -#endif free(a); global.at(i).erase(global.at(i).begin() + j); pthread_mutex_unlock(&G_Mixer.mutex_recs); @@ -277,7 +263,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa } if (found) { optimize(); - chanHasActions(chan); + setChanHasActionsStatus(chan); gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } @@ -287,7 +273,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void deleteActions(int chan, int frame_a, int frame_b, char type) @@ -304,7 +290,7 @@ void deleteActions(int chan, int frame_a, int frame_b, char type) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void clearAll() @@ -336,7 +322,7 @@ void clearAll() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void optimize() @@ -358,7 +344,7 @@ void optimize() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void sortActions() @@ -376,7 +362,7 @@ void sortActions() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void updateBpm(float oldval, float newval, int oldquanto) @@ -417,7 +403,7 @@ void updateBpm(float oldval, float newval, int oldquanto) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void updateSamplerate(int systemRate, int patchRate) @@ -457,7 +443,7 @@ void updateSamplerate(int systemRate, int patchRate) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void expand(int old_fpb, int new_fpb) @@ -488,7 +474,7 @@ void expand(int old_fpb, int new_fpb) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void shrink(int new_fpb) @@ -515,26 +501,29 @@ void shrink(int new_fpb) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void chanHasActions(int index) +void setChanHasActionsStatus(int index) { Channel *ch = G_Mixer.getChannelByIndex(index); if (global.size() == 0) { ch->hasActions = false; return; } - for (unsigned i=0; ihasActions; i++) { - for (unsigned j=0; jhasActions; j++) { - if (global.at(i).at(j)->chan == index) + for (unsigned i=0; ichan == index) { ch->hasActions = true; + return; + } } } + ch->hasActions = false; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue) @@ -562,7 +551,7 @@ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int getAction(int chan, char action, int frame, struct action **out) @@ -580,7 +569,7 @@ int getAction(int chan, char action, int frame, struct action **out) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void startOverdub(int index, char actionMask, int frame) @@ -622,7 +611,7 @@ void startOverdub(int index, char actionMask, int frame) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void stopOverdub(int frame) @@ -651,9 +640,10 @@ void stopOverdub(int frame) /* remove any nested action between keypress----keyrel, then record */ - if (!nullLoop) + 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); + } if (!ringLoop && !nullLoop) { rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame); @@ -673,7 +663,7 @@ void stopOverdub(int frame) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void print() diff --git a/src/core/recorder.h b/src/core/recorder.h index 363323f..95a8b65 100644 --- a/src/core/recorder.h +++ b/src/core/recorder.h @@ -36,20 +36,6 @@ #include "const.h" #include "mixer.h" -#ifdef WITH_VST - -/* before including aeffetx(x).h we must define __cdecl, otherwise VST - * headers can't be compiled correctly. In windows __cdecl is already - * defined. */ - - #ifdef __GNUC__ - #ifndef _WIN32 - #define __cdecl - #endif - #endif - #include "../deps/vst/aeffectx.h" -#endif - using std::vector; @@ -61,14 +47,15 @@ using std::vector; * [global3]-->[vector<_action*>3]-->[a0][a1][a2] 3[frames4] * */ -namespace recorder { - +namespace recorder +{ /* action * struct containing fields to describe an atomic action. Note from * VST sdk: parameter values, like all VST parameters, are declared as * floats with an inclusive range of 0.0 to 1.0 (fValue). */ -struct action { +struct action +{ int chan; // channel index, i.e. Channel->index int type; int frame; // redundant info, used by helper functions @@ -80,7 +67,8 @@ struct action { * a group of two actions (keypress+keyrel, muteon+muteoff) used during * the overdub process */ -struct composite { +struct composite +{ action a1; action a2; }; @@ -97,11 +85,11 @@ extern bool sortedActions; // are actions sorted via sortAction void init(); -/* chanHasActions +/* setChanHasActionsStatus * Check if the channel has at least one action recorded. If false, sets * ch->hasActions = false. Used after an action deletion. */ -void chanHasActions(int chan); +void setChanHasActionsStatus(int chan); /* canRec * can a channel rec an action? Call this one BEFORE rec(). */ diff --git a/src/core/sampleChannel.cpp b/src/core/sampleChannel.cpp index 48ee17b..3b7d5e1 100644 --- a/src/core/sampleChannel.cpp +++ b/src/core/sampleChannel.cpp @@ -713,7 +713,7 @@ bool SampleChannel::allocEmpty(int frames, int samplerate, int takeId) return false; w->name = "TAKE-" + gItoa(takeId); - w->pathfile = gGetCurrentPath() + gGetSlash() + w->name; + w->pathfile = gGetCurrentPath() + G_SLASH + w->name; wave = w; status = STATUS_OFF; begin = 0; @@ -975,11 +975,16 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize, else { /* fillChan only if frame != 0. If you call fillChan on frame == 0 - * a duplicate call to fillChan occurs with loss of data. */ + a duplicate call to fillChan occurs with loss of data. Yeah, but + what happens if an action really occurs on frame 0 (and it happens, + for example when you start the sequencer from the firt beat)? Cheat + time! Shift a little bit the frame, so that it's no longer zero. */ status = STATUS_PLAY; sendMidiLplay(); - if (frame != 0) + if (frame == 0) + frame = 2; + //if (frame != 0) tracker = fillChan(vChan, tracker, frame); } } diff --git a/src/core/wave.cpp b/src/core/wave.cpp index 28b3a42..4bdffc9 100644 --- a/src/core/wave.cpp +++ b/src/core/wave.cpp @@ -33,8 +33,12 @@ #include #include "../utils/utils.h" #include "../utils/log.h" -#include "wave.h" #include "init.h" +#include "const.h" +#include "wave.h" + + +using std::string; Wave::Wave() @@ -239,12 +243,12 @@ int Wave::resample(int quality, int newRate) /* -------------------------------------------------------------------------- */ -std::string Wave::basename() const +string Wave::basename(bool ext) const { - return gStripExt(gBasename(pathfile.c_str()).c_str()); + return ext ? gBasename(pathfile) : gStripExt(gBasename(pathfile)); } -std::string Wave::extension() const +string Wave::extension() const { return gGetExt(pathfile.c_str()); } @@ -255,10 +259,10 @@ std::string Wave::extension() const void Wave::updateName(const char *n) { - std::string ext = gGetExt(pathfile.c_str()); - name = gStripExt(gBasename(n).c_str()); - pathfile = gDirname(pathfile.c_str()) + gGetSlash() + name + "." + ext; - isLogical = true; + string ext = gGetExt(pathfile.c_str()); + name = gStripExt(gBasename(n).c_str()); + pathfile = gDirname(pathfile.c_str()) + G_SLASH + name + "." + ext; + isLogical = true; /* a wave with updated name must become logical, since the underlying * file does not exist yet. */ diff --git a/src/core/wave.h b/src/core/wave.h index 237e52f..f602667 100644 --- a/src/core/wave.h +++ b/src/core/wave.h @@ -36,6 +36,9 @@ #include +using std::string; + + class Wave { private: @@ -52,8 +55,8 @@ public: ~Wave(); Wave(const Wave &other); - std::string pathfile; // full path + sample name - std::string name; // sample name (changeable) + string pathfile; // full path + sample name + string name; // sample name (changeable) float *data; int size; // wave size (size in stereo: size / 2) @@ -67,8 +70,8 @@ public: inline void channels(int v) { inHeader.channels = v; } inline void frames (int v) { inHeader.frames = v; } - std::string basename () const; - std::string extension() const; + string basename (bool ext=false) const; + string extension() const; void updateName(const char *n); int open (const char *f); diff --git a/src/glue/glue.cpp b/src/glue/glue.cpp index 7acd5fb..ff1670c 100644 --- a/src/glue/glue.cpp +++ b/src/glue/glue.cpp @@ -711,7 +711,7 @@ void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val) ch->panRight= 0.0f + val; char buf[8]; - sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100)); + sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100)); win->panNum->value(buf); } else if (val == 1.0f) { @@ -724,7 +724,7 @@ void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val) ch->panRight= 1.0f; char buf[8]; - sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100)); + sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100)); win->panNum->value(buf); } win->panNum->redraw(); diff --git a/src/glue/storage.cpp b/src/glue/storage.cpp index daa2fc7..d517736 100644 --- a/src/glue/storage.cpp +++ b/src/glue/storage.cpp @@ -32,6 +32,7 @@ #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" @@ -62,17 +63,6 @@ extern PluginHost G_PluginHost; #endif -static void __glue_setProgressBar__(class gProgress *status, float v) -{ - status->value(status->value() + v); - //Fl::check(); - Fl::wait(0); -} - - -/* -------------------------------------------------------------------------- */ - - #ifdef WITH_VST static void __glue_fillPatchGlobalsPlugins__(vector *host, vector *patch) @@ -160,7 +150,8 @@ static void __glue_fillPatchGlobals__(const string &name) /* -------------------------------------------------------------------------- */ -int glue_savePatch(const string &fullPath, const string &name, bool isProject) +static bool __glue_savePatch__(const string &fullPath, const string &name, + bool isProject) { G_Patch.init(); @@ -170,38 +161,88 @@ int glue_savePatch(const string &fullPath, const string &name, bool isProject) if (G_Patch.write(fullPath)) { gu_update_win_label(name.c_str()); - gLog("[glue] patch saved as %s\n", fullPath.c_str()); - return 1; + gLog("[glue_savePatch] patch saved as %s\n", fullPath.c_str()); + return true; } - return 0; + return false; } /* -------------------------------------------------------------------------- */ -int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProject) +void glue_savePatch(void *data) { - /* try to load the new JSON-based patch. If it fails, fall back to deprecated - * one. */ + gdSaveBrowser *browser = (gdSaveBrowser*) data; + string name = browser->getName(); + string fullPath = browser->getCurrentPath() + G_SLASH + gStripExt(name) + ".gptc"; + + if (name == "") { + gdAlert("Please choose a file name."); + return; + } + + if (gFileExists(fullPath.c_str())) + if (!gdConfirmWin("Warning", "File exists: overwrite?")) + return; + + if (__glue_savePatch__(fullPath, name, false)) { // false == not a project + G_Conf.patchPath = gDirname(fullPath); + browser->do_callback(); + } + else + gdAlert("Unable to save the patch!"); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_loadPatch(void *data) +{ + gdLoadBrowser *browser = (gdLoadBrowser*) data; + string fullPath = browser->getSelectedItem(); + bool isProject = gIsProject(browser->getSelectedItem()); + + browser->showStatusBar(); gLog("[glue] loading %s...\n", fullPath.c_str()); string fileToLoad = fullPath; // patch file to read from string basePath = ""; // base path, in case of reading from a project if (isProject) { - fileToLoad = fullPath + gGetSlash() + gStripExt(gBasename(fullPath)) + ".gptc"; - basePath = fullPath.c_str() + gGetSlash(); + fileToLoad = fullPath + G_SLASH + gStripExt(gBasename(fullPath)) + ".gptc"; + basePath = fullPath + G_SLASH; } - int res = G_Patch.read(fileToLoad); + /* try to load the new JSON-based patch. If it fails, fall back to deprecated + * one. */ + + int res = G_Patch.read(fileToLoad); + bool deprecated = false; if (res == PATCH_UNREADABLE) { gLog("[glue] failed reading JSON-based patch. Trying with the deprecated method\n"); - return glue_loadPatch__DEPR__(gBasename(fileToLoad).c_str(), fileToLoad.c_str(), status, isProject); + deprecated = true; + res = glue_loadPatch__DEPR__(gBasename(fileToLoad).c_str(), fileToLoad.c_str(), + browser->getStatusBar(), isProject); + } + + if (res != PATCH_READ_OK) { + if (res == PATCH_UNREADABLE) + isProject ? gdAlert("This project is unreadable.") : gdAlert("This patch is unreadable."); + else + if (res == PATCH_INVALID) + isProject ? gdAlert("This project is not valid.") : gdAlert("This patch is not valid."); + + browser->hideStatusBar(); + return; + } + else + if (deprecated) { + browser->do_callback(); + return; } - if (res != PATCH_READ_OK) - return res; /* close all other windows. This prevents segfault if plugin * windows GUIs are on. */ @@ -213,7 +254,8 @@ int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProje glue_resetToInitState(false, false); - __glue_setProgressBar__(status, 0.1f); + browser->setStatusBar(0.1f); + //__glue_setProgressBar__(status, 0.1f); /* Add common stuff, columns and channels. Also increment the progress bar * by 0.8 / total_channels steps. */ @@ -229,7 +271,8 @@ int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProje ch->readPatch(basePath, k, &G_Patch, &G_Mixer.mutex_plugins, G_Conf.samplerate, G_Conf.rsmpQuality); } - __glue_setProgressBar__(status, steps); + //__glue_setProgressBar__(status, steps); + browser->setStatusBar(steps); } } @@ -245,14 +288,15 @@ int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProje /* save patchPath by taking the last dir of the broswer, in order to * reuse it the next time */ - G_Conf.patchPath = gDirname(fullPath.c_str()); + G_Conf.patchPath = gDirname(fullPath); /* refresh GUI */ gu_updateControls(); gu_update_win_label(G_Patch.name.c_str()); - __glue_setProgressBar__(status, 1.0f); + browser->setStatusBar(0.1f); + //__glue_setProgressBar__(status, 1.0f); gLog("[glue] patch loaded successfully\n"); @@ -263,7 +307,7 @@ int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProje #endif - return res; + browser->do_callback(); } @@ -359,13 +403,28 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat /* -------------------------------------------------------------------------- */ -int glue_saveProject(const string &folderPath, const string &projName) +void glue_saveProject(void *data) { - if (!gDirExists(folderPath.c_str()) && !gMkdir(folderPath.c_str())) { - gLog("[glue] unable to make project directory!\n"); - return 0; + gdSaveBrowser *browser = (gdSaveBrowser*) data; + string name = browser->getName(); + string folderPath = browser->getCurrentPath(); //browser->getSelectedItem(); + string fullPath = folderPath + G_SLASH + gStripExt(name) + ".gprj"; + + if (name == "") { + gdAlert("Please choose a project name."); + return; + } + + if (gIsProject(fullPath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?")) + return; + + if (!gDirExists(fullPath.c_str()) && !gMkdir(fullPath.c_str())) { + gLog("[glue_saveProject] unable to make project directory!\n"); + return; } + gLog("[glue_saveProject] project dir created: %s\n", fullPath.c_str()); + /* copy all samples inside the folder. Takes and logical ones are saved * via glue_saveSample() */ @@ -382,7 +441,7 @@ int glue_saveProject(const string &folderPath, const string &projName) /* update the new samplePath: everything now comes from the project * folder (folderPath). Also remove any existing file. */ - string samplePath = folderPath + gGetSlash() + ch->wave->basename() + "." + ch->wave->extension(); + string samplePath = fullPath + G_SLASH + ch->wave->basename(true); if (gFileExists(samplePath.c_str())) remove(samplePath.c_str()); @@ -390,8 +449,63 @@ int glue_saveProject(const string &folderPath, const string &projName) ch->wave->pathfile = samplePath; } - string gptcPath = folderPath + gGetSlash() + gStripExt(projName.c_str()) + ".gptc"; - glue_savePatch(gptcPath, projName, true); // true == it's a project + string gptcPath = fullPath + G_SLASH + gStripExt(name.c_str()) + ".gptc"; + if (__glue_savePatch__(gptcPath, name, true)) // true == it's a project + browser->do_callback(); + else + gdAlert("Unable to save the project!"); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_loadSample(void *data) +{ + gdLoadBrowser *browser = (gdLoadBrowser*) data; + string fullPath = browser->getSelectedItem(); + + if (fullPath.empty()) + return; + + int res = glue_loadChannel((SampleChannel*) browser->getChannel(), fullPath.c_str()); - return 1; + if (res == SAMPLE_LOADED_OK) { + G_Conf.samplePath = gDirname(fullPath); + browser->do_callback(); + mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open + } + else + mainWin->keyboard->printChannelMessage(res); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_saveSample(void *data) +{ + gdSaveBrowser *browser = (gdSaveBrowser*) data; + string name = browser->getName(); + string folderPath = browser->getSelectedItem(); + + if (name == "") { + gdAlert("Please choose a file name."); + return; + } + + /* bruteforce check extension. */ + + string filePath = folderPath + G_SLASH + gStripExt(name) + ".wav"; + + if (gFileExists(filePath)) + if (!gdConfirmWin("Warning", "File exists: overwrite?")) + return; + + if (((SampleChannel*)browser->getChannel())->save(filePath.c_str())) { + G_Conf.samplePath = gDirname(folderPath); + browser->do_callback(); + } + else + gdAlert("Unable to save this sample!"); } diff --git a/src/glue/storage.h b/src/glue/storage.h index f7d05c1..98be8e8 100644 --- a/src/glue/storage.h +++ b/src/glue/storage.h @@ -40,9 +40,11 @@ using std::string; using std::vector; -int glue_loadPatch (const string &fullPath, class gProgress *status, bool isProject); +void glue_loadPatch (void *data); int glue_loadPatch__DEPR__(const char *fname, const char *fpath, class gProgress *status, bool isProject); -int glue_savePatch (const string &fullPath, const string &name, bool isProject); -int glue_saveProject(const string &folderPath, const string &projName); +void glue_savePatch (void *data); +void glue_saveProject(void *data); +void glue_saveSample (void *data); +void glue_loadSample (void *data); #endif diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp index 246a36e..3e0e614 100644 --- a/src/gui/dialogs/gd_about.cpp +++ b/src/gui/dialogs/gd_about.cpp @@ -73,8 +73,13 @@ gdAbout::gdAbout() "Version " G_VERSION_STR " (" BUILD_DATE ")\n\n" "Developed by Monocasual\n" "Based on FLTK (%d.%d.%d), RtAudio (%s),\n" - "RtMidi (%s), libsamplerate, Jansson (%s) \n" - "and libsndfile\n\n" + "RtMidi (%s), Libsamplerate, Jansson (%s),\n" + "Libsndfile" +#ifdef WITH_VST + ", JUCE (%d.%d.%d)\n\n" +#else + "\n\n" +#endif "Released under the terms of the GNU General\n" "Public License (GPL v3)\n\n" "News, infos, contacts and documentation:\n" @@ -82,7 +87,12 @@ gdAbout::gdAbout() FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, kernelAudio::getRtAudioVersion().c_str(), kernelMidi::getRtMidiVersion().c_str(), - JANSSON_VERSION); + JANSSON_VERSION +#ifdef WITH_VST + , JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER); +#else + ); +#endif int tw = 0; int th = 0; diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp index 544e83f..ddfcdaf 100644 --- a/src/gui/dialogs/gd_actionEditor.cpp +++ b/src/gui/dialogs/gd_actionEditor.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_actionEditor * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -147,7 +147,7 @@ gdActionEditor::gdActionEditor(Channel *chan) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gdActionEditor::~gdActionEditor() { @@ -162,14 +162,14 @@ gdActionEditor::~gdActionEditor() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdActionEditor::cb_zoomIn(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomIn(); } void gdActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomOut(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdActionEditor::__cb_zoomIn() { @@ -209,7 +209,7 @@ void gdActionEditor::__cb_zoomIn() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdActionEditor::__cb_zoomOut() { @@ -245,7 +245,7 @@ void gdActionEditor::__cb_zoomOut() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdActionEditor::update() { @@ -258,7 +258,7 @@ void gdActionEditor::update() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gdActionEditor::handle(int e) { @@ -274,7 +274,7 @@ int gdActionEditor::handle(int e) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gdActionEditor::getActionType() { @@ -291,9 +291,9 @@ int gdActionEditor::getActionType() { } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gGridTool::gGridTool(int x, int y, gdActionEditor *parent) @@ -320,7 +320,7 @@ gGridTool::gGridTool(int x, int y, gdActionEditor *parent) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gGridTool::~gGridTool() { @@ -329,13 +329,13 @@ gGridTool::~gGridTool() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gGridTool::cb_changeType(Fl_Widget *w, void *p) { ((gGridTool*)p)->__cb_changeType(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gGridTool::__cb_changeType() { @@ -344,7 +344,7 @@ void gGridTool::__cb_changeType() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ bool gGridTool::isOn() { @@ -352,7 +352,7 @@ bool gGridTool::isOn() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gGridTool::getValue() { @@ -370,7 +370,7 @@ int gGridTool::getValue() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gGridTool::calc() { @@ -413,7 +413,7 @@ void gGridTool::calc() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gGridTool::getSnapPoint(int v) { @@ -435,7 +435,7 @@ int gGridTool::getSnapPoint(int v) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gGridTool::getSnapFrame(int v) { @@ -464,7 +464,7 @@ int gGridTool::getSnapFrame(int v) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gGridTool::getCellSize() { diff --git a/src/gui/dialogs/gd_browser.cpp b/src/gui/dialogs/gd_browser.cpp index f427abb..448ad74 100644 --- a/src/gui/dialogs/gd_browser.cpp +++ b/src/gui/dialogs/gd_browser.cpp @@ -27,111 +27,65 @@ * -------------------------------------------------------------------------- */ -#include "../../core/mixer.h" #include "../../core/graphics.h" #include "../../core/wave.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../../core/patch_DEPR_.h" -#include "../../core/patch.h" #include "../../core/conf.h" #include "../../glue/glue.h" #include "../../glue/channel.h" #include "../../glue/storage.h" +#include "../../utils/gui_utils.h" #include "../elems/ge_browser.h" #include "../elems/ge_channel.h" -#include "../elems/ge_keyboard.h" #include "gd_browser.h" -#include "gd_mainWindow.h" -#include "gd_warnings.h" using std::string; -extern Patch_DEPR_ G_Patch_DEPR_; -extern Patch G_Patch; -extern Conf G_Conf; -extern Mixer G_Mixer; -extern gdMainWindow *mainWin; +extern Conf G_Conf; -gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int type, int stackType) - : gWindow (396, 302, title), - ch (ch), - type (type), - stackType(stackType) +gdBaseBrowser::gdBaseBrowser(int x, int y, int w, int h, const string &title, + const string &path, void (*callback)(void*)) + : gWindow(x, y, w, h, title.c_str()), callback(callback) { set_non_modal(); - browser = new gBrowser(8, 36, 380, 230); - Fl_Group *group_btn = new Fl_Group(8, 274, 380, 20); - gBox *b = new gBox(8, 274, 204, 20); // spacer window border <-> buttons - ok = new gClick(308, 274, 80, 20); - cancel = new gClick(220, 274, 80, 20, "Cancel"); - status = new gProgress(8, 274, 204, 20); - status->minimum(0); - status->maximum(1); - status->hide(); // show the bar only if necessary - group_btn->resizable(b); - group_btn->end(); - - Fl_Group *group_upd = new Fl_Group(8, 8, 380, 25); - if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! - name = new gInput(208, 8, 152, 20); - if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! - where = new gInput(8, 8, 192, 20); - else - where = new gInput(8, 8, 352, 20); - updir = new gClick(368, 8, 20, 20, "", updirOff_xpm, updirOn_xpm); - group_upd->resizable(where); - group_upd->end(); - - end(); - - resizable(browser); - size_range(w(), h(), 0, 0); + 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->end(); + groupTop->resizable(where); where->readonly(true); where->cursor_color(COLOR_BG_DARK); + where->value(path.c_str()); - if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! - ok->label("Save"); - else - ok->label("Load"); + updir->callback(cb_up, (void*) this); - if (type == BROWSER_LOAD_PATCH) - ok->callback(cb_load_patch, (void*)this); - else - if (type == BROWSER_LOAD_SAMPLE) - ok->callback(cb_load_sample, (void*)this); - else - if (type == BROWSER_SAVE_PATCH) { - ok->callback(cb_save_patch, (void*)this); - name->value(G_Patch.name == "" ? "my_patch.gptc" : G_Patch.name.c_str()); - name->maximum_size(MAX_PATCHNAME_LEN+5); // +5 for ".gptc" - } - else - if (type == BROWSER_SAVE_SAMPLE) { - ok->callback(cb_save_sample, (void*)this); - name->value(((SampleChannel*)ch)->wave->name.c_str()); - } - else - if (type == BROWSER_SAVE_PROJECT) { - ok->callback(cb_save_project, (void*)this); - name->value(gStripExt(G_Patch.name).c_str()); - } + browser = new gBrowser(8, groupTop->y()+groupTop->h()+8, w-16, h-73); + browser->loadDir(path); + if (path == G_Conf.browserLastPath) + browser->preselect(G_Conf.browserPosition, G_Conf.browserLastValue); - ok->shortcut(FL_Enter); + Fl_Group *groupButtons = new Fl_Group(8, browser->y()+browser->h()+8, w-16, 20); + ok = new gClick(w-88, groupButtons->y(), 80, 20); + cancel = new gClick(w-ok->w()-96, groupButtons->y(), 80, 20, "Cancel"); + status = new gProgress(8, groupButtons->y(), cancel->x()-16, 20); + status->minimum(0); + status->maximum(1); + status->hide(); // show the bar only if necessary + groupButtons->resizable(status); + groupButtons->end(); + + end(); - updir->callback(cb_up, (void*)this); - cancel->callback(cb_close, (void*)this); - browser->callback(cb_down, this); - browser->path_obj = where; - browser->init(initPath); + cancel->callback(cb_close, (void*) this); - if (G_Conf.browserW) - resize(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH); + resizable(browser); + size_range(320, 200); gu_setFavicon(this); show(); @@ -141,189 +95,175 @@ gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int t /* -------------------------------------------------------------------------- */ -gdBrowser::~gdBrowser() { +gdBaseBrowser::~gdBaseBrowser() +{ G_Conf.browserX = x(); G_Conf.browserY = y(); G_Conf.browserW = w(); G_Conf.browserH = h(); + G_Conf.browserPosition = browser->position(); + G_Conf.browserLastPath = gDirname(browser->getSelectedItem()); + G_Conf.browserLastValue = browser->value(); } /* -------------------------------------------------------------------------- */ -void gdBrowser::cb_load_patch (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_load_patch(); } -void gdBrowser::cb_load_sample (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_load_sample(); } -void gdBrowser::cb_save_sample (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_sample(); } -void gdBrowser::cb_save_patch (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_patch(); } -void gdBrowser::cb_save_project(Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_project(); } -void gdBrowser::cb_down (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_down(); } -void gdBrowser::cb_up (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_up(); } -void gdBrowser::cb_close (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_close(); } +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 gdBrowser::__cb_load_patch() { +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); + where->value(browser->getCurrentDir().c_str()); +} - if (browser->text(browser->value()) == NULL) - return; - bool isProject = gIsProject(browser->get_selected_item()); - int res = glue_loadPatch(browser->get_selected_item(), status, isProject); +/* -------------------------------------------------------------------------- */ + - if (res == PATCH_UNREADABLE) { - status->hide(); - if (isProject) - gdAlert("This project is unreadable."); - else - gdAlert("This patch is unreadable."); - } - else - if (res == PATCH_INVALID) { - status->hide(); - if (isProject) - gdAlert("This project is not valid."); - else - gdAlert("This patch is not valid."); - } - else - do_callback(); +void gdBaseBrowser::__cb_close() { + do_callback(); } /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_save_sample() { - - if (strcmp(name->value(), "") == 0) { /// FIXME glue business - gdAlert("Please choose a file name."); - return; - } +void gdBaseBrowser::setStatusBar(float v) +{ + status->value(status->value() + v); + Fl::wait(0); +} - /* bruteforce check extension. */ - string filename = gStripExt(name->value()); - char fullpath[PATH_MAX]; - sprintf(fullpath, "%s/%s.wav", where->value(), filename.c_str()); +/* -------------------------------------------------------------------------- */ - if (gFileExists(fullpath)) - if (!gdConfirmWin("Warning", "File exists: overwrite?")) - return; - if (((SampleChannel*)ch)->save(fullpath)) - do_callback(); - else - gdAlert("Unable to save this sample!"); +string gdBaseBrowser::getSelectedItem() +{ + return browser->getSelectedItem(); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_load_sample() { - if (browser->text(browser->value()) == NULL) - return; +gdSaveBrowser::gdSaveBrowser(int x, int y, int w, int h, const string &title, + const string &path, const string &_name, void (*cb)(void*), Channel *ch) + : gdBaseBrowser(x, y, w, h, title, path, cb) +{ + channel = ch; - int res = glue_loadChannel((SampleChannel*) ch, browser->get_selected_item()); + where->size(groupTop->w()-236, 20); - if (res == SAMPLE_LOADED_OK) { - do_callback(); - mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open - } - else - mainWin->keyboard->printChannelMessage(res); + name = new gInput(where->x()+where->w()+8, 8, 200, 20); + name->value(_name.c_str()); + groupTop->add(name); + + browser->callback(cb_down, (void*) this); + + ok->label("Save"); + ok->callback(cb_save, (void*) this); + ok->shortcut(FL_ENTER); } /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_down() { - const char *path = browser->get_selected_item(); - if (!path) // when click on an empty area - return; - if (!gIsDir(path)) { - - /* set the name of the patch/sample/project as the selected item */ - - if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) { - if (gIsProject(path)) { - string tmp = browser->text(browser->value()); - tmp.erase(0, 4); - name->value(tmp.c_str()); - } - else - name->value(browser->text(browser->value())); - } +void gdSaveBrowser::cb_save(Fl_Widget *v, void *p) { ((gdSaveBrowser*)p)->__cb_save(); } +void gdSaveBrowser::cb_down(Fl_Widget *v, void *p) { ((gdSaveBrowser*)p)->__cb_down(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdSaveBrowser::__cb_down() +{ + string path = browser->getSelectedItem(); + + if (path.empty()) // when click on an empty area return; + + /* if the selected item is a directory just load its content. If it's a file + * use it as the file name (i.e. fill name->value()). */ + + if (gIsDir(path)) { + browser->loadDir(path); + where->value(browser->getCurrentDir().c_str()); } - browser->clear(); - browser->down_dir(path); - browser->sort(); + else + name->value(browser->getSelectedItem(false).c_str()); } /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_up() { - browser->clear(); - browser->up_dir(); - browser->sort(); +void gdSaveBrowser::__cb_save() +{ + callback((void*) this); } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_save_patch() +gdLoadBrowser::gdLoadBrowser(int x, int y, int w, int h, const string &title, + const string &path, void (*cb)(void*), Channel *ch) + : gdBaseBrowser(x, y, w, h, title, path, cb) { - if (strcmp(name->value(), "") == 0) { /// FIXME glue business - gdAlert("Please choose a file name."); - return; - } + channel = ch; - string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gptc"; + where->size(groupTop->w()-updir->w()-8, 20); - if (gFileExists(fullpath.c_str())) - if (!gdConfirmWin("Warning", "File exists: overwrite?")) - return; + browser->callback(cb_down, (void*) this); - if (glue_savePatch(fullpath, name->value(), false)) // false == not a project - do_callback(); - else - gdAlert("Unable to save the patch!"); + ok->label("Load"); + ok->callback(cb_load, (void*) this); + ok->shortcut(FL_ENTER); } + + /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_save_project() -{ - if (strcmp(name->value(), "") == 0) { /// FIXME glue business - gdAlert("Please choose a project name."); - return; - } +void gdLoadBrowser::cb_load(Fl_Widget *v, void *p) { ((gdLoadBrowser*)p)->__cb_load(); } +void gdLoadBrowser::cb_down(Fl_Widget *v, void *p) { ((gdLoadBrowser*)p)->__cb_down(); } - string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gprj"; - if (gIsProject(fullpath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?")) - return; +/* -------------------------------------------------------------------------- */ - if (glue_saveProject(fullpath, name->value())) - do_callback(); - else - gdAlert("Unable to save the project!"); + +void gdLoadBrowser::__cb_load() +{ + callback((void*) this); } /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_close() { - do_callback(); +void gdLoadBrowser::__cb_down() +{ + string path = browser->getSelectedItem(); + + if (path.empty() || !gIsDir(path)) // when click on an empty area or not a dir + return; + + browser->loadDir(path); + where->value(browser->getCurrentDir().c_str()); } diff --git a/src/gui/dialogs/gd_browser.h b/src/gui/dialogs/gd_browser.h index 7700fab..bf797ec 100644 --- a/src/gui/dialogs/gd_browser.h +++ b/src/gui/dialogs/gd_browser.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_browser * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef GD_BROWSER_H @@ -33,64 +33,103 @@ #include #include +#include "../elems/ge_mixed.h" #include "../elems/ge_window.h" -/* TODO - this class must be subclassed into gdPluginBrowser, gdFileBrowser, - * and so on. It's a real mess right now. */ +class gdBaseBrowser : public gWindow +{ +protected: -class gdBrowser : public gWindow { - -private: - static void cb_down(Fl_Widget *v, void *p); - static void cb_up (Fl_Widget *v, void *p); - static void cb_load_sample (Fl_Widget *v, void *p); - static void cb_save_sample (Fl_Widget *v, void *p); - static void cb_load_patch (Fl_Widget *v, void *p); - static void cb_save_patch (Fl_Widget *v, void *p); - static void cb_save_project(Fl_Widget *v, void *p); - static void cb_close (Fl_Widget *w, void *p); - - inline void __cb_down(); - inline void __cb_up(); - inline void __cb_load_sample(); - inline void __cb_save_sample(); - inline void __cb_save_project(); - inline void __cb_load_patch(); - inline void __cb_save_patch(); - inline void __cb_close(); - + class Fl_Group *groupTop; class gBrowser *browser; class gClick *ok; class gClick *cancel; class gInput *where; - class gInput *name; class gClick *updir; class gProgress *status; - class Channel *ch; + static void cb_up (Fl_Widget *v, void *p); + static void cb_close(Fl_Widget *w, void *p); + + inline void __cb_up (); + inline void __cb_close(); + + /* Callback + * Fired when the save/load button is pressed. */ + + void (*callback)(void*); + + class Channel *channel; + +public: + + gdBaseBrowser(int x, int y, int w, int h, const string &title, + const string &path, void (*callback)(void*)); + + ~gdBaseBrowser(); + + /* getSelectedItem + * Return the full path of the selected file. */ + + string getSelectedItem(); + + /* setStatusBar + * Increment status bar for progress tracking. */ + + 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(); } +}; + + +/* -------------------------------------------------------------------------- */ + + +class gdSaveBrowser : public gdBaseBrowser +{ +private: + + class gInput *name; + + static void cb_down(Fl_Widget *v, void *p); + static void cb_save(Fl_Widget *w, void *p); + + inline void __cb_down(); + inline void __cb_save(); + +public: + + gdSaveBrowser(int x, int y, int w, int h, const string &title, + const string &path, const string &name, void (*callback)(void*), + class Channel *ch); + + string getName() { return name->value(); } +}; - /* browser type: see const.h */ - /** FIXME internal enum: - * enum browserType { - * TYPE_A, - * TYPE_B, - * .... - * }; */ - int type; +/* -------------------------------------------------------------------------- */ - /* PluginHost_DEPR_ stack type. Used only when loading plugins */ - int stackType; +class gdLoadBrowser : public gdBaseBrowser +{ +private: - char selectedFile[FILENAME_MAX]; + static void cb_load(Fl_Widget *w, void *p); + static void cb_down(Fl_Widget *v, void *p); + + inline void __cb_load(); + inline void __cb_down(); public: - gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0); - ~gdBrowser(); - char* SelectedFile(); + gdLoadBrowser(int x, int y, int w, int h, const string &title, + const string &path, void (*callback)(void*), class Channel *ch); }; #endif diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp index 8e47cc3..5d7da03 100644 --- a/src/gui/dialogs/gd_config.cpp +++ b/src/gui/dialogs/gd_config.cpp @@ -669,12 +669,18 @@ void gTabMidi::fetchMidiMaps() midiMap->deactivate(); return; } + for (unsigned i=0; iadd(imap); if (G_Conf.midiMapPath == imap) midiMap->value(i); } + + /* Preselect the 0 midimap if nothing is selected but midimaps exist. */ + + if (midiMap->value() == -1 && G_MidiMap.maps.size() > 0) + midiMap->value(0); } @@ -910,7 +916,7 @@ void gTabPlugins::__cb_scan(Fl_Widget *w) { info->show(); G_PluginHost.scanDir(folderPath->value(), cb_onScan, (void*) this); - G_PluginHost.saveList(gGetHomePath() + gGetSlash() + "plugins.xml"); + G_PluginHost.saveList(gGetHomePath() + G_SLASH + "plugins.xml"); info->hide(); updateCount(); } diff --git a/src/gui/dialogs/gd_editor.cpp b/src/gui/dialogs/gd_editor.cpp index b6d4d5c..501edfe 100644 --- a/src/gui/dialogs/gd_editor.cpp +++ b/src/gui/dialogs/gd_editor.cpp @@ -202,7 +202,7 @@ gdEditor::gdEditor(SampleChannel *ch) if (ch->panRight < 1.0f) { char buf[8]; - sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100)); + sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100)); pan->value(ch->panRight); panNum->value(buf); } @@ -212,7 +212,7 @@ gdEditor::gdEditor(SampleChannel *ch) } else { char buf[8]; - sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100)); + sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100)); pan->value(2.0f - ch->panLeft); panNum->value(buf); } diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp index c10021b..b2012c2 100644 --- a/src/gui/dialogs/gd_mainWindow.cpp +++ b/src/gui/dialogs/gd_mainWindow.cpp @@ -43,6 +43,7 @@ #include "../../core/conf.h" #include "../../core/pluginHost.h" #include "../../glue/glue.h" +#include "../../glue/storage.h" #include "../elems/ge_keyboard.h" #include "gd_warnings.h" #include "gd_bpmInput.h" @@ -57,6 +58,7 @@ extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; +extern Patch G_Patch; extern Conf G_Conf; extern gdMainWindow *mainWin; extern bool G_quit; @@ -67,6 +69,7 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg : gWindow(W, H, title) { Fl::visible_focus(0); + Fl::background(25, 25, 25); Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2); // custom box G_BOX @@ -109,6 +112,7 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg add(keyboard); callback(cb_endprogram); gu_setFavicon(this); + show(argc, argv); } @@ -317,7 +321,11 @@ void gMenu::__cb_file() if (strcmp(m->label(), "Open patch or project...") == 0) { - gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH); + //gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH); + //gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + gWindow *childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Load patch or project", + G_Conf.patchPath, glue_loadPatch, NULL); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } @@ -325,12 +333,16 @@ void gMenu::__cb_file() 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 gdBrowser("Save Patch", G_Conf.patchPath.c_str(), 0, BROWSER_SAVE_PATCH); + gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Save patch", + G_Conf.patchPath, G_Patch.name, glue_savePatch, NULL); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Save project...") == 0) { - gWindow *childWin = new gdBrowser("Save Project", G_Conf.patchPath.c_str(), 0, BROWSER_SAVE_PROJECT); + gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, + G_Conf.browserW, G_Conf.browserH, "Save project", + G_Conf.patchPath, G_Patch.name, glue_saveProject, NULL); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } diff --git a/src/gui/dialogs/gd_pluginList.cpp b/src/gui/dialogs/gd_pluginList.cpp index 9ea9d22..433284f 100644 --- a/src/gui/dialogs/gd_pluginList.cpp +++ b/src/gui/dialogs/gd_pluginList.cpp @@ -147,12 +147,6 @@ void gdPluginList::__cb_addPlugin() { stackType, ch); addSubWindow(pc); pc->callback(cb_refreshList, (void*)this); // 'this' refers to gdPluginList - -#if 0 - gdBrowser *b = new gdBrowser("Browse Plugin_DEPR_", G_Conf.pluginPath.c_str(), ch, BROWSER_LOAD_PLUGIN, stackType); - addSubWindow(b); - b->callback(cb_refreshList, (void*)this); // 'this' refers to gdPluginList -#endif } @@ -363,32 +357,6 @@ void gdPlugin::__cb_openPluginWindow() else { w = new gdPluginWindow(pPlugin); } -#if 0 - - /* TODO - at the moment you can open a window for each plugin in the stack. - * This is not consistent with the rest of the gui. You can avoid this by - * calling - * - * gu_openSubWindow(this, new gdPluginWindow(pPlugin), WID_FX); - * - * instead of the following code. - * - * EDIT 2 - having only 1 plugin window would be very uncomfortable */ - - if (!pParent->hasWindow(pPlugin->getId()+1)) { - gWindow *w; - if (pPlugin->hasEditor()) -#ifdef __APPLE__ - w = new gdPluginWindowGUImac(pPlugin); -#else - w = new gdPluginWindowGUI(pPlugin); -#endif - else - w = new gdPluginWindow(pPlugin); - w->setId(pPlugin->getId()+1); - pParent->addSubWindow(w); - } -#endif } diff --git a/src/gui/dialogs/gd_pluginWindowGUI.cpp b/src/gui/dialogs/gd_pluginWindowGUI.cpp index 01fe5fa..b50b1f4 100644 --- a/src/gui/dialogs/gd_pluginWindowGUI.cpp +++ b/src/gui/dialogs/gd_pluginWindowGUI.cpp @@ -52,27 +52,36 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin) show(); #ifndef __APPLE__ + Fl::check(); + #endif gLog("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n", (void*) this, (void*) fl_xid(this)); - pPlugin->initEditor(); - #if defined(__APPLE__) + void *cocoaWindow = (void*) fl_xid(this); cocoa_setWindowSize(cocoaWindow, pPlugin->getEditorW(), pPlugin->getEditorH()); pPlugin->showEditor(cocoa_getViewFromWindow(cocoaWindow)); + #else + pPlugin->showEditor((void*) fl_xid(this)); + #endif - resize(0, 0, pPlugin->getEditorW(), pPlugin->getEditorH()); + int pluginW = pPlugin->getEditorW(); + int pluginH = pPlugin->getEditorH(); + + printf("w=%d h=%d\n", Fl::w(), Fl::h()); + + resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH); Fl::add_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this); - copy_label(pPlugin->getName().toStdString().c_str()); + copy_label(pPlugin->getName().toRawUTF8()); } diff --git a/src/gui/elems/ge_actionChannel.cpp b/src/gui/elems/ge_actionChannel.cpp index fdedf08..81b453a 100644 --- a/src/gui/elems/ge_actionChannel.cpp +++ b/src/gui/elems/ge_actionChannel.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionChannel * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -44,11 +44,13 @@ extern Mixer G_Mixer; extern Conf G_Conf; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch) - : gActionWidget(x, y, 200, 40, pParent), ch(ch), selected(NULL) + : gActionWidget(x, y, 200, 40, pParent), + ch (ch), + selected (NULL) { size(pParent->totalWidth, h()); @@ -58,49 +60,49 @@ gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChan for (unsigned i=0; ichan == pParent->chan->index) { - - /* don't show actions > than the grey area */ - - if (recorder::frames.at(i) > G_Mixer.totalFrames) - continue; - - /* skip the killchan actions in a singlepress channel. They cannot be recorded - * in such mode, but they can exist if you change from another mode to singlepress */ - - if (ra->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS) - continue; - - /* also filter out ACTION_KEYREL: it's up to gAction to find the other piece - * (namely frame_b) */ - - if (ra->type & (ACTION_KEYPRESS | ACTION_KILLCHAN)) { - int ax = x+(ra->frame/pParent->zoom); - gAction *a = new gAction( - ax, // x - y+4, // y - h()-8, // h - ra->frame, // frame_a - i, // n. of recordings - pParent, // pointer to the pParent window - ch, // pointer to SampleChannel - false, // record = false: don't record it, we are just displaying it! - ra->type); // type of action - add(a); - } - } + recorder::action *action = recorder::global.at(i).at(j); + + /* Don't show actions: + - that don't belong to the displayed channel (!= pParent->chan->index); + - that are covered by the grey area (> G_Mixer.totalFrames); + - of type ACTION_KILLCHAN in a SINGLE_PRESS channel. They cannot be + recorded in such mode, but they can exist if you change from another + mode to singlepress; + - of type ACTION_KEYREL in a SINGLE_PRESS channel. It's up to gAction to + find the other piece (namely frame_b) + - not of types ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN */ + + if ((action->chan != pParent->chan->index) || + (recorder::frames.at(i) > G_Mixer.totalFrames) || + (action->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS) || + (action->type == ACTION_KEYREL && ch->mode == SINGLE_PRESS) || + (action->type & ~(ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN)) + ) + continue; + + int ax = x + (action->frame / pParent->zoom); + gAction *a = new gAction( + ax, // x + y + 4, // y + h() - 8, // h + action->frame, // frame_a + i, // n. of recordings + pParent, // pointer to the pParent window + ch, // pointer to SampleChannel + false, // record = false: don't record it, we are just displaying it! + action->type); // type of action + add(a); } } end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -gAction *gActionChannel::getSelectedAction() { +gAction *gActionChannel::getSelectedAction() +{ for (int i=0; ix(); int action_w = ((gAction*)child(i))->w(); @@ -111,11 +113,11 @@ gAction *gActionChannel::getSelectedAction() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gActionChannel::updateActions() { - +void gActionChannel::updateActions() +{ /* when zooming, don't delete and re-add actions, just MOVE them. This * function shifts the action by a zoom factor. Those singlepress are * stretched, as well */ @@ -138,11 +140,11 @@ void gActionChannel::updateActions() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gActionChannel::draw() { - +void gActionChannel::draw() +{ /* draw basic boundaries (+ beat bars) and hide the unused area. Then * draw the children (the actions) */ @@ -161,11 +163,11 @@ void gActionChannel::draw() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int gActionChannel::handle(int e) { - +int gActionChannel::handle(int e) +{ int ret = Fl_Group::handle(e); /* do nothing if the widget is deactivated. It could happen for loopmode @@ -177,69 +179,72 @@ int gActionChannel::handle(int e) { switch (e) { case FL_DRAG: { - if (selected != NULL) { // if you don't drag an empty area - /* if onLeftEdge o onRightEdge are true it means that you're resizing - * an action. Otherwise move the widget. */ + if (selected == NULL) { // if you drag an empty area + ret = 1; + break; + } - if (selected->onLeftEdge || selected->onRightEdge) { + /* if onLeftEdge o onRightEdge are true it means that you're resizing + * an action. Otherwise move the widget. */ - /* some checks: a) cannot resize an action < N pixels, b) no beyond zero, - * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */ + if (selected->onLeftEdge || selected->onRightEdge) { - if (selected->onRightEdge) { + /* some checks: a) cannot resize an action < N pixels, b) no beyond zero, + * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */ - int aw = Fl::event_x()-selected->x(); - int ah = selected->h(); + if (selected->onRightEdge) { - if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH) - aw = gAction::MIN_WIDTH; - else - if (Fl::event_x() > pParent->coverX) - aw = pParent->coverX-selected->x(); + int aw = Fl::event_x()-selected->x(); + int ah = selected->h(); - selected->size(aw, ah); - } - else { + if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH) + aw = gAction::MIN_WIDTH; + else + if (Fl::event_x() > pParent->coverX) + aw = pParent->coverX-selected->x(); - int ax = Fl::event_x(); - int ay = selected->y(); - int aw = selected->x()-Fl::event_x()+selected->w(); - int ah = selected->h(); + selected->size(aw, ah); + } + else { - if (Fl::event_x() < x()) { - ax = x(); - aw = selected->w()+selected->x()-x(); - } - else - if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) { - ax = selected->x()+selected->w()-gAction::MIN_WIDTH; - aw = gAction::MIN_WIDTH; - } - selected->resize(ax, ay, aw, ah); + int ax = Fl::event_x(); + int ay = selected->y(); + int aw = selected->x()-Fl::event_x()+selected->w(); + int ah = selected->h(); + + if (Fl::event_x() < x()) { + ax = x(); + aw = selected->w()+selected->x()-x(); } + else + if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) { + ax = selected->x()+selected->w()-gAction::MIN_WIDTH; + aw = gAction::MIN_WIDTH; + } + selected->resize(ax, ay, aw, ah); } + } - /* move the widget around */ + /* move the widget around */ + else { + int real_x = Fl::event_x() - actionPickPoint; + if (real_x < x()) // don't go beyond the left border + selected->position(x(), selected->y()); + else + if (real_x+selected->w() > pParent->coverX+x()) // don't go beyond the right border + selected->position(pParent->coverX+x()-selected->w(), selected->y()); else { - int real_x = Fl::event_x() - actionPickPoint; - if (real_x < x()) // don't go beyond the left border - selected->position(x(), selected->y()); - else - if (real_x+selected->w() > pParent->coverX+x()) // don't go beyond the right border - selected->position(pParent->coverX+x()-selected->w(), selected->y()); - else { - if (pParent->gridTool->isOn()) { - int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1; - selected->position(snpx, selected->y()); - } - else - selected->position(real_x, selected->y()); + if (pParent->gridTool->isOn()) { + int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1; + selected->position(snpx, selected->y()); } + else + selected->position(real_x, selected->y()); } - redraw(); } + redraw(); ret = 1; break; } @@ -399,23 +404,23 @@ int gActionChannel::handle(int e) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -bool gActionChannel::actionCollides(int frame) { - +bool gActionChannel::actionCollides(int frame) +{ /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't * overlap the head (frame) of the new one. First the general case, yet. */ bool collision = false; for (int i=0; iframe_a == frame) + if (((gAction*) child(i))->frame_a == frame) collision = true; if (ch->mode == SINGLE_PRESS) { for (int i=0; iframe_b && frame >= c->frame_a) collision = true; } @@ -425,15 +430,9 @@ bool gActionChannel::actionCollides(int frame) { } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -const int gAction::MIN_WIDTH = 8; - - -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ /** TODO - index is useless? @@ -485,11 +484,11 @@ gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEdito } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void gAction::draw() { +void gAction::draw() +{ int color; if (selected) /// && gActionChannel !disabled color = COLOR_BD_1; @@ -515,11 +514,11 @@ void gAction::draw() { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -int gAction::handle(int e) { +int gAction::handle(int e) +{ /* ret = 0 sends the event to the parent window. */ int ret = 0; @@ -565,11 +564,11 @@ int gAction::handle(int e) { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void gAction::addAction() { +void gAction::addAction() +{ /* always check frame parity */ if (frame_a % 2 != 0) @@ -597,11 +596,11 @@ void gAction::addAction() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gAction::delAction() { - +void gAction::delAction() +{ /* if SINGLE_PRESS you must delete both the keypress and the keyrelease * actions. */ @@ -619,11 +618,11 @@ void gAction::delAction() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gAction::moveAction(int frame_a) { - +void gAction::moveAction(int frame_a) +{ /* easy one: delete previous action and record the new ones. As usual, * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame * value. */ @@ -652,25 +651,28 @@ void gAction::moveAction(int frame_a) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int gAction::absx() { +int gAction::absx() +{ return x() - parent->ac->x(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int gAction::xToFrame_a() { +int gAction::xToFrame_a() +{ return (absx()) * parent->zoom; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int gAction::xToFrame_b() { +int gAction::xToFrame_b() +{ return (absx() + w()) * parent->zoom; } diff --git a/src/gui/elems/ge_actionChannel.h b/src/gui/elems/ge_actionChannel.h index 38bc8d8..051feea 100644 --- a/src/gui/elems/ge_actionChannel.h +++ b/src/gui/elems/ge_actionChannel.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionChannel * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,11 +24,13 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + #ifndef GE_ACTIONCHANNEL_H #define GE_ACTIONCHANNEL_H + #include #include #include "../../utils/gui_utils.h" @@ -37,8 +39,8 @@ #include "ge_actionWidget.h" -class gAction : public Fl_Box { - +class gAction : public Fl_Box +{ private: bool selected; @@ -48,6 +50,7 @@ private: char type; // type of action public: + gAction(int x, int y, int h, int frame_a, unsigned index, gdActionEditor *parent, class SampleChannel *ch, bool record, char type); @@ -80,14 +83,15 @@ public: bool onRightEdge; bool onLeftEdge; - static const int MIN_WIDTH; + static const int MIN_WIDTH = 8; }; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -class gActionChannel : public gActionWidget { +class gActionChannel : public gActionWidget +{ private: @@ -125,6 +129,7 @@ private: bool actionCollides(int frame); public: + gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch); void draw(); int handle(int e); diff --git a/src/gui/elems/ge_browser.cpp b/src/gui/elems/ge_browser.cpp index 8ae7d09..be64cc8 100644 --- a/src/gui/elems/ge_browser.cpp +++ b/src/gui/elems/ge_browser.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_browser * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,24 +24,27 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include #include "../../core/const.h" #include "../../utils/utils.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, const char *L) - : Fl_Hold_Browser(x, y, w, h, L) +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); @@ -52,256 +55,117 @@ gBrowser::gBrowser(int x, int y, int w, int h, const char *L) this->hscrollbar.selection_color(COLOR_BG_1); this->hscrollbar.labelcolor(COLOR_BD_1); this->hscrollbar.slider(G_BOX); -} - - -/* ------------------------------------------------------------------ */ - - -gBrowser::~gBrowser() {} - - -/* ------------------------------------------------------------------ */ - -void gBrowser::init(const char *init_path) { - - gLog("[gBrowser] init path = '%s'\n", init_path); - - if (init_path == NULL || !gIsDir(init_path)) { -#if defined(__linux__) || defined(__APPLE__) - path_obj->value("/home"); -#elif defined(_WIN32) - - /* SHGetFolderPath is deprecated. We should use SHGetKnownFolderPath - * but that would break compatibility with XP. On Vista, GetFolderPath - * is a wrapper of GetKnownFolderPath, so no problem. */ - - char winRoot[1024]; - SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, winRoot); // si parte dal Desktop - path_obj->value(winRoot); -#endif - gLog("[gBrowser] init_path null or invalid, using default\n"); - } - else - path_obj->value(init_path); - - refresh(); - sort(); + take_focus(); // let it have focus on startup } -/* ------------------------------------------------------------------ */ - - -void gBrowser::refresh() { - DIR *dp; - struct dirent *ep; - dp = opendir(path_obj->value()); - if (dp != NULL) { - while ((ep = readdir(dp))) { - - /* skip: - * - "." e ".." - * - hidden files */ - - if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) { - if (ep->d_name[0] != '.') { - - /* is it a folder? add square brackets. Is it a file? Append - * a '/' (on Windows seems useless, though) */ - - std::string file = path_obj->value(); - file.insert(file.size(), gGetSlash()); - file += ep->d_name; - - if (gIsDir(file.c_str())) { - char name[PATH_MAX]; - sprintf(name, "@b[%s]", ep->d_name); - add(name); - } - else - if (gIsProject(file.c_str())) { - char name[PATH_MAX]; - sprintf(name, "@i@b%s", ep->d_name); - add(name); - } - else - add(ep->d_name); - } - } - } - closedir(dp); - } - else - gLog("[gBrowser] Couldn't open the directory '%s'\n", path_obj->value()); -} +/* -------------------------------------------------------------------------- */ -/* ------------------------------------------------------------------ */ +void gBrowser::loadDir(const string &dir) +{ + currentDir = dir; + load(currentDir.c_str()); + /* hide "../", it just screws up things */ -void gBrowser::sort() { - for (int t=1; t<=size(); t++) - for (int r=t+1; r<=size(); r++) - if (strcmp(text(t), text(r)) > 0) - swap(t,r); + if (text(1) != NULL && strcmp(text(1), "../") == 0) + remove(1); } -/* ------------------------------------------------------------------ */ - - -void gBrowser::up_dir() { - - /* updir = remove last folder from the path. Start from strlen(-1) to - * skip the trailing slash */ - - int i = strlen(path_obj->value())-1; +/* -------------------------------------------------------------------------- */ - /* on Windows an updir from the path "X:\" (3 chars long) must redirect - * to the list of available devices. */ - -#if defined(_WIN32) - if (i <= 3 || !strcmp(path_obj->value(), "All drives")) { - path_obj->value("All drives"); - showDrives(); - return; - } - else { - while (i >= 0) { - if (path_obj->value()[i] == '\\') - break; - i--; - } - - /* delete the last part of the string, from i to len-i, ie everything - * after the "/" */ - - std::string tmp = path_obj->value(); - tmp.erase(i, tmp.size()-i); - - /* if tmp.size == 2 we have something like 'C:'. Add a trailing - * slash */ - - if (tmp.size() == 2) - tmp += "\\"; - - path_obj->value(tmp.c_str()); - refresh(); - } -#elif defined(__linux__) || defined (__APPLE__) - while (i >= 0) { - if (path_obj->value()[i] == '/') +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; - i--; - } - - /* i == 0 means '/', the root dir. It's meaningless to go updir */ - - if (i==0) - path_obj->value("/"); - else { - - /* delete the last part of the string, from i to len-i, ie everything - * after the "/" */ - - std::string tmp = path_obj->value(); - tmp.erase(i, tmp.size()-i); - path_obj->value(tmp.c_str()); - } - refresh(); -#endif + 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; } +/* -------------------------------------------------------------------------- */ -/* ------------------------------------------------------------------ */ - -void gBrowser::down_dir(const char *path) { - path_obj->value(path); - refresh(); +string gBrowser::getCurrentDir() +{ + return normalize(gGetRealPath(currentDir)); } -/* ------------------------------------------------------------------ */ - - -const char *gBrowser::get_selected_item() { - - /* click on an empty line */ - - if (text(value()) == NULL) - return NULL; - - selected_item = text(value()); - - /* @ = formatting marks. - * @b = bold, i.e. a directory. Erease '@b[' and ']' */ - - if (selected_item[0] == '@') { - if (selected_item[1] == 'b') { - selected_item.erase(0, 3); - selected_item.erase(selected_item.size()-1, 1); - } - else - if (selected_item[1] == 'i') - selected_item.erase(0, 4); - } +/* -------------------------------------------------------------------------- */ -#if defined(__linux__) || defined(__APPLE__) - /* add path to file name, to get an absolute path. Avoid double - * slashes like '//' */ - - if (strcmp("/", path_obj->value())) - selected_item.insert(0, "/"); - - selected_item.insert(0, path_obj->value()); - return selected_item.c_str(); -#elif defined(_WIN32) - - /* if path is 'All drives' we are in the devices list and the user - * has clicked on a device such as 'X:\' */ +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(gGetRealPath(currentDir + G_SLASH + normalize(text(value())))); +} - if (strcmp(path_obj->value(), "All drives") == 0) - return selected_item.c_str(); - else { - /* add '\' if the path is like 'X:\' */ +/* -------------------------------------------------------------------------- */ - if (strlen(path_obj->value()) > 3) /// shouln't it be == 3? - selected_item.insert(0, "\\"); - selected_item.insert(0, path_obj->value()); - return selected_item.c_str(); - } -#endif +void gBrowser::preselect(int pos, int line) +{ + position(pos); + select(line); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -#ifdef _WIN32 -void gBrowser::showDrives() { - - /* GetLogicalDriveStrings fills drives like that: - * - * a:\[null]b:\[null]c:\[null]...[null][null] - * - * where [null] stands for \0. */ +string gBrowser::normalize(const string &s) +{ + string out = s; - char drives[64]; - char *i = drives; // pointer to 0th element in drives - GetLogicalDriveStrings(64, drives); + /* our crappy version of Clang doesn't seem to support std::string::back() */ - /* code stolen from the web, still unknown. (Jan 09, 2012). */ +#ifdef __APPLE__ + if (out[out.length() - 1] == G_SLASH) +#else + if (out.back() == G_SLASH) +#endif - while (*i) { - add(i); - i = &i[strlen(i) + 1]; - } + out = out.substr(0, out.size()-1); + return out; } - -#endif diff --git a/src/gui/elems/ge_browser.h b/src/gui/elems/ge_browser.h index 0fbc1b7..e338143 100644 --- a/src/gui/elems/ge_browser.h +++ b/src/gui/elems/ge_browser.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_browser * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,45 +24,52 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + #ifndef GE_BROWSER_H #define GE_BROWSER_H #include -#include +#include #include #include "ge_mixed.h" -class gBrowser : public Fl_Hold_Browser { + +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, const char *L=0); - ~gBrowser(); - void init(const char *init_path=NULL); - void refresh(); - void sort(); - void up_dir(); - void down_dir(const char *path); - const char *get_selected_item(); - /* path_obj - * the actual path*/ + gBrowser(int x, int y, int w, int h); - class gInput *path_obj; + /* init + * Initialize browser and show 'dir' as initial directory. */ - /* selected_item - * choosen item */ + void loadDir(const string &dir); - std::string selected_item; + /* getSelectedItem + * Return the full path or just the displayed name of the i-th selected item. + * Always with the trailing slash! */ -#ifdef _WIN32 -private: + string getSelectedItem(bool fullPath=true); - /* showDrives [WIN32 only] - * lists all the available drivers */ + string getCurrentDir(); - void showDrives(); -#endif + void preselect(int position, int line); + + int handle(int e); }; #endif diff --git a/src/gui/elems/ge_mixed.cpp b/src/gui/elems/ge_mixed.cpp index 7069e6c..60abf9e 100644 --- a/src/gui/elems/ge_mixed.cpp +++ b/src/gui/elems/ge_mixed.cpp @@ -612,9 +612,10 @@ void gBaseButton::trimLabel() len--; } } - else + else { out = ""; - copy_label(out.c_str()); + } + copy_label(out.c_str()); } diff --git a/src/gui/elems/ge_sampleChannel.cpp b/src/gui/elems/ge_sampleChannel.cpp index d098faa..3838a9e 100644 --- a/src/gui/elems/ge_sampleChannel.cpp +++ b/src/gui/elems/ge_sampleChannel.cpp @@ -38,6 +38,7 @@ #include "../../core/midiChannel.h" #include "../../glue/glue.h" #include "../../glue/channel.h" +#include "../../glue/storage.h" #include "../../utils/gui_utils.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" @@ -366,20 +367,21 @@ void gSampleChannel::__cb_readActions() void gSampleChannel::openBrowser(int type) { - const char *title = ""; + gWindow *childWin = NULL; switch (type) { case BROWSER_LOAD_SAMPLE: - title = "Browse 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: - title = "Save Sample"; - break; - case -1: - title = "Edit 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; } - gWindow *childWin = new gdBrowser(title, G_Conf.samplePath.c_str(), ch, type); - gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + if (childWin) + gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); } diff --git a/src/utils/log.cpp b/src/utils/log.cpp index 0834d63..1ebef9f 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -72,8 +72,12 @@ void gLog(const char *format, ...) { return; va_list args; va_start(args, format); - if (mode == LOG_MODE_FILE && stat == true) + if (mode == LOG_MODE_FILE && stat == true) { vfprintf(f, format, args); +#ifdef _WIN32 + fflush(f); +#endif + } else vprintf(format, args); va_end(args); diff --git a/src/utils/string.cpp b/src/utils/string.cpp new file mode 100644 index 0000000..167ed83 --- /dev/null +++ b/src/utils/string.cpp @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * utils + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "string.h" +#include + + +using std::string; + + +string gGetRealPath(const string &path) +{ + string out = ""; + +#if defined(__linux__) || defined(__APPLE__) + + char *buf = realpath(path.c_str(), NULL); + +#else // Windows + + char *buf = _fullpath(NULL, path.c_str(), PATH_MAX); + +#endif + + if (buf) { + out = buf; + free(buf); + } + return out; +} diff --git a/src/utils/string.h b/src/utils/string.h new file mode 100644 index 0000000..758b742 --- /dev/null +++ b/src/utils/string.h @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * utils + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef __UTILS_STRING_H__ +#define __UTILS_STRING_H__ + + +#include +#include +#include +#include "log.h" + + +using std::string; + + +string gGetRealPath(const string &path); + +#endif diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 1f7a117..16e00f4 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -27,7 +27,6 @@ * -------------------------------------------------------------------------- */ -#include "utils.h" #if defined(_WIN32) // getcwd (unix) or __getcwd (win) #include #include @@ -48,13 +47,16 @@ #include // basename unix #include // getpwuid #endif +#include "../core/const.h" +#include "utils.h" using std::string; using std::vector; -bool gFileExists(const char *filename) { +bool gFileExists(const char *filename) +{ FILE *fh = fopen(filename, "rb"); if (!fh) { return 0; @@ -66,6 +68,12 @@ bool gFileExists(const char *filename) { } +bool gFileExists(const string &filename) +{ + return gFileExists(filename.c_str()); +} + + /* -------------------------------------------------------------------------- */ @@ -111,6 +119,11 @@ bool gIsDir(const char *path) } +bool gIsDir(const string &path) +{ + return gIsDir(path.c_str()); +} + /* -------------------------------------------------------------------------- */ @@ -152,18 +165,11 @@ bool gMkdir(const string &path) /* -------------------------------------------------------------------------- */ -/* TODO - avoid this shit, just wrap the other call */ -string gBasename(const char *path) -{ - string out = path; - out.erase(0, out.find_last_of(gGetSlash().c_str())+1); - return out; -} string gBasename(const string &s) { string out = s; - out.erase(0, out.find_last_of(gGetSlash().c_str())+1); + out.erase(0, out.find_last_of(G_SLASH_STR) + 1); return out; } @@ -171,10 +177,12 @@ string gBasename(const string &s) /* -------------------------------------------------------------------------- */ -string gDirname(const char *path) +string gDirname(const string &path) { + if (path.empty()) + return ""; string out = path; - out.erase(out.find_last_of(gGetSlash().c_str())); + out.erase(out.find_last_of(G_SLASH_STR)); return out; } @@ -241,11 +249,11 @@ string gStripExt(const string &s) /* -------------------------------------------------------------------------- */ -bool gIsProject(const char *path) +bool gIsProject(const string &path) { /** FIXME - checks too weak */ - if (gGetExt(path) == "gprj" && gDirExists(path)) + if (gGetExt(path.c_str()) == "gprj" && gDirExists(path)) return 1; return 0; } @@ -286,18 +294,6 @@ string gGetProjectName(const char *path) } -/* -------------------------------------------------------------------------- */ - - -string gGetSlash() -{ -#if defined(_WIN32) - return "\\"; -#else - return "/"; -#endif -} - /* -------------------------------------------------------------------------- */ diff --git a/src/utils/utils.h b/src/utils/utils.h index c8da493..dd6ecd0 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -42,25 +42,27 @@ using std::vector; bool gFileExists(const char *path); +bool gFileExists(const string &path); bool gDirExists(const char *path); bool gDirExists(const string &path); bool gIsDir(const char *path); +bool gIsDir(const string &path); -bool gIsProject(const char *path); +bool gIsProject(const string &path); bool gIsPatch(const char *path); +bool gIsPatch(const string &path); bool gMkdir(const char *path); bool gMkdir(const string &path); -string gBasename(const char *path); string gBasename(const string &s); string gReplace(string in, const string& search, const string& replace); -string gDirname(const char *path); +string gDirname(const string &s); string gTrim(const char *path); string gTrim(const string &s); @@ -78,8 +80,6 @@ string gStripExt(const string &s); string gGetProjectName(const char *path); // TODO - useless! -string gGetSlash(); - string gItoa(int i); void gSplit(string in, string sep, vector *v); diff --git a/tests/resources/test.wav b/tests/resources/test.wav new file mode 100644 index 0000000..1e52d36 Binary files /dev/null and b/tests/resources/test.wav differ diff --git a/tests/wave.cpp b/tests/wave.cpp index cf91ab9..930e7fa 100644 --- a/tests/wave.cpp +++ b/tests/wave.cpp @@ -1,5 +1,3 @@ -#ifdef RUN_TESTS_WITH_LOCAL_FILES - #include "../src/core/wave.h" #include "catch.hpp" @@ -17,10 +15,10 @@ TEST_CASE("Test Wave class") SECTION("test read & write") { - REQUIRE(w1.open("test.wav") == 1); + REQUIRE(w1.open("tests/resources/test.wav") == 1); REQUIRE(w1.readData() == 1); - REQUIRE(w1.rate() == 11025); - REQUIRE(w1.channels() == 2); + REQUIRE(w1.rate() == 44100); + REQUIRE(w1.channels() == 1); REQUIRE(w1.basename() == "test"); REQUIRE(w1.extension() == "wav"); REQUIRE(w1.writeData("test-write.wav") == true); @@ -31,8 +29,8 @@ TEST_CASE("Test Wave class") Wave w2(w1); REQUIRE(w2.size == w1.size); REQUIRE(w2.isLogical == true); - //REQUIRE(w2.rate() == 11025); // WHAT THE FUCK??? - REQUIRE(w2.channels() == 2); + //REQUIRE(w2.rate() == 44100); // WHAT THE FUCK??? + REQUIRE(w2.channels() == 1); REQUIRE(w2.writeData("test-write.wav") == true); } @@ -45,5 +43,3 @@ TEST_CASE("Test Wave class") REQUIRE(w3.writeData("test-write.wav") == true); } } - -#endif // #ifdef RUN_TESTS_WITH_LOCAL_FILES