From 3c4d2accf5f58cd154ed98b5e8741b3e472d0365 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jarom=C3=ADr=20Mike=C5=A1?= Date: Wed, 2 Dec 2015 09:47:59 +0100 Subject: [PATCH] Imported Upstream version 0.11.0~dfsg1 --- .travis.yml | 11 +- ChangeLog | 12 + Makefile.am | 52 +- configure.ac | 10 +- src/core/channel.cpp | 164 +++- src/core/channel.h | 19 +- src/core/conf.cpp | 2 +- src/core/conf.h | 4 +- src/core/const.h | 88 +- .../{dataStorage.cpp => dataStorageIni.cpp} | 10 +- src/core/{dataStorage.h => dataStorageIni.h} | 16 +- src/core/dataStorageJson.cpp | 148 ++++ src/core/dataStorageJson.h | 65 ++ src/core/init.cpp | 15 +- src/core/midiChannel.cpp | 53 +- src/core/midiChannel.h | 35 +- src/core/midiMapConf.h | 4 +- src/core/mixer.cpp | 89 +- src/core/mixerHandler.cpp | 115 ++- src/core/mixerHandler.h | 15 +- src/core/patch.cpp | 835 ++++++------------ src/core/patch.h | 187 +++- src/core/patch_DEPR_.cpp | 614 +++++++++++++ src/core/patch_DEPR_.h | 94 ++ src/core/pluginHost.cpp | 10 +- src/core/pluginHost.h | 6 +- src/core/recorder.cpp | 8 +- src/core/sampleChannel.cpp | 114 ++- src/core/sampleChannel.h | 37 +- src/glue/glue.cpp | 174 +--- src/glue/glue.h | 8 - src/glue/storage.cpp | 382 ++++++++ src/glue/storage.h | 56 ++ src/gui/dialogs/gd_about.cpp | 35 +- src/gui/dialogs/gd_beatsInput.cpp | 1 - src/gui/dialogs/gd_browser.cpp | 79 +- src/gui/dialogs/gd_config.cpp | 8 +- src/gui/dialogs/gd_mainWindow.cpp | 4 +- src/gui/elems/ge_channel.cpp | 4 +- src/gui/elems/ge_channelButton.cpp | 21 +- src/gui/elems/ge_channelButton.h | 8 +- src/gui/elems/ge_column.cpp | 42 +- src/gui/elems/ge_column.h | 5 + src/gui/elems/ge_keyboard.cpp | 59 +- src/gui/elems/ge_keyboard.h | 28 +- src/gui/elems/ge_midiChannel.cpp | 7 +- src/gui/elems/ge_sampleChannel.cpp | 18 +- src/gui/elems/ge_sampleChannel.h | 2 +- src/main.cpp | 14 +- src/utils/gui_utils.cpp | 9 +- src/utils/gvector.h | 146 +++ src/utils/utils.cpp | 68 +- src/utils/utils.h | 143 +-- tests/patch.cpp | 229 +++++ 54 files changed, 3055 insertions(+), 1327 deletions(-) rename src/core/{dataStorage.cpp => dataStorageIni.cpp} (91%) rename src/core/{dataStorage.h => dataStorageIni.h} (88%) create mode 100644 src/core/dataStorageJson.cpp create mode 100644 src/core/dataStorageJson.h create mode 100644 src/core/patch_DEPR_.cpp create mode 100644 src/core/patch_DEPR_.h create mode 100644 src/glue/storage.cpp create mode 100644 src/glue/storage.h create mode 100644 src/utils/gvector.h create mode 100644 tests/patch.cpp diff --git a/.travis.yml b/.travis.yml index 98ce5e8..f254f19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: cpp compiler: gcc -notifications: +notifications: email: recipients: - giadaloopmachine@gmail.com @@ -13,10 +13,15 @@ before_install: - 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 -before_script: +before_script: - wget http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-2.1.0.tar.gz - tar -xvf rtmidi-2.1.0.tar.gz - - cd rtmidi-2.1.0 && ./configure --with-jack --with-alsa && make && sudo make install || true + - cd rtmidi-2.1.0 && ./configure --with-jack --with-alsa && make && sudo make install || true + - cd .. + - wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz + - tar -xvf jansson-2.7.tar.gz + - cd jansson-2.7 && ./configure && make && sudo make install || true + - sudo ldconfig - cd .. - ./autogen.sh - ./configure --target=linux --enable-vst diff --git a/ChangeLog b/ChangeLog index 620e85c..466f6df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,18 @@ +0.11.0 --- 2015 . 12 .02 +- New JSON-based patch system +- Properly store column width in patch +- Port all const char* strings to std::string in patch/project glue layer +- Switch to SemVer-like internal versioning system +- More source code reorganization +- Fix potential memory leaks in Mixer +- Fix missing static link of RtMidi on Linux +- Unable to store pitch values > 2.0 (fixed) +- Missing assigned key after opening patch (fixed) + + 0.10.2 --- 2015 . 10 . 21 - Setup Travis CI automated builds - Add base framework for unit testing (with Catch) diff --git a/Makefile.am b/Makefile.am index 1c99cc3..84b2f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,16 +37,22 @@ src/core/kernelMidi.h \ src/core/kernelMidi.cpp \ src/core/graphics.h \ src/core/graphics.cpp \ +src/core/patch_DEPR_.h \ +src/core/patch_DEPR_.cpp \ src/core/patch.h \ src/core/patch.cpp \ src/core/recorder.h \ src/core/recorder.cpp \ src/core/mixer.h \ src/core/mixer.cpp \ -src/core/dataStorage.h \ -src/core/dataStorage.cpp \ +src/core/dataStorageIni.h \ +src/core/dataStorageIni.cpp \ +src/core/dataStorageJson.h \ +src/core/dataStorageJson.cpp \ src/glue/glue.h \ src/glue/glue.cpp \ +src/glue/storage.h \ +src/glue/storage.cpp \ src/gui/dialogs/gd_keyGrabber.h \ src/gui/dialogs/gd_keyGrabber.cpp \ src/gui/dialogs/gd_about.h \ @@ -123,6 +129,7 @@ src/utils/log.h \ src/utils/log.cpp \ src/utils/gui_utils.h \ src/utils/gui_utils.cpp \ +src/utils/gvector.h \ src/utils/utils.h \ src/utils/utils.cpp @@ -132,19 +139,19 @@ src/utils/utils.cpp if LINUX giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm \ src/deps/rtaudio-mod/librtaudio.a -ljack -lasound -lpthread -ldl \ - -lpulse-simple -lpulse -lsamplerate -lrtmidi + -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson endif 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 + -lpthreadGC2 -ljansson giada_LDFLAGS = -mwindows -static giada_SOURCES += resource.rc endif if OSX giada_LDADD = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \ - -lsamplerate + -lsamplerate -ljansson giada_CXXFLAGS = -m32 giada_LDFLAGS = -m32 -framework CoreAudio -framework Cocoa -framework Carbon \ -framework CoreMIDI -framework CoreFoundation @@ -153,7 +160,7 @@ endif # used only under MinGW to compile the resource.rc file (program icon) resource.o: - windres src/ext/resource.rc -o resource.o + windres src/ext/resource.rc -o resource.o # custom rtaudio @@ -161,23 +168,30 @@ src/deps/rtaudio-mod/librtaudio.a: @cd src/deps/rtaudio-mod; echo "Building RtAudio for Linux..."; \ ./configure --with-jack --with-alsa --with-pulse; \ make; - + # make test -------------------------------------------------------------------- TESTS = giada_tests check_PROGRAMS = giada_tests -giada_tests_SOURCES = \ -tests/main.cpp \ -tests/conf.cpp \ -tests/utils.cpp \ -src/core/conf.cpp \ -src/core/dataStorage.cpp \ -src/utils/utils.cpp \ -src/utils/log.cpp - -# Ancient gcc on Travis complains about missing parentheses. - -giada_tests_CXXFLAGS = -Wno-parentheses +giada_tests_SOURCES = \ +tests/main.cpp \ +tests/conf.cpp \ +tests/patch.cpp \ +tests/utils.cpp \ +src/core/conf.cpp \ +src/core/patch.cpp \ +src/core/dataStorageIni.cpp \ +src/core/dataStorageJson.cpp \ +src/utils/utils.cpp \ +src/utils/log.cpp + +giada_tests_LDADD = -ljansson + +# Ancient gcc on Travis complains about missing parentheses. +# Catch also goes crazy with GCC 5.x (https://github.com/philsquared/Catch/issues/487) +# --std=c++11 + +giada_tests_CXXFLAGS = -Wno-parentheses -std=c++0x # make rename ------------------------------------------------------------------ diff --git a/configure.ac b/configure.ac index a501966..695cf23 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ # prereq & init AC_PREREQ(2.60) -AC_INIT([giada], [0.10], [giadaloopmachine@gmail.com]) +AC_INIT([giada], [0.11], [giadaloopmachine@gmail.com]) AC_CONFIG_SRCDIR([src/main.cpp]) AM_INIT_AUTOMAKE([subdir-objects]) @@ -100,6 +100,14 @@ AC_CHECK_HEADER( ) AC_LANG_POP +AC_LANG_PUSH([C++]) +AC_CHECK_HEADER( + [jansson.h], + [], + [AC_MSG_ERROR([library 'Jansson' not found!])] +) +AC_LANG_POP + AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [sndfile.h], diff --git a/src/core/channel.cpp b/src/core/channel.cpp index 85ee975..762ba0d 100644 --- a/src/core/channel.cpp +++ b/src/core/channel.cpp @@ -32,15 +32,18 @@ #include "channel.h" #include "pluginHost.h" #include "kernelMidi.h" +#include "patch_DEPR_.h" #include "patch.h" #include "wave.h" #include "mixer.h" #include "mixerHandler.h" #include "conf.h" +#include "patch.h" #include "waveFx.h" #include "midiMapConf.h" +extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; @@ -124,23 +127,23 @@ void Channel::sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offse /* -------------------------------------------------------------------------- */ -void Channel::readPatchMidiIn(int i) +void Channel::readPatchMidiIn_DEPR_(int i) { - midiIn = G_Patch.getMidiValue(i, "In"); - midiInKeyPress = G_Patch.getMidiValue(i, "InKeyPress"); - midiInKeyRel = G_Patch.getMidiValue(i, "InKeyRel"); - midiInKill = G_Patch.getMidiValue(i, "InKill"); - midiInVolume = G_Patch.getMidiValue(i, "InVolume"); - midiInMute = G_Patch.getMidiValue(i, "InMute"); - midiInSolo = G_Patch.getMidiValue(i, "InSolo"); + midiIn = G_Patch_DEPR_.getMidiValue(i, "In"); + midiInKeyPress = G_Patch_DEPR_.getMidiValue(i, "InKeyPress"); + midiInKeyRel = G_Patch_DEPR_.getMidiValue(i, "InKeyRel"); + midiInKill = G_Patch_DEPR_.getMidiValue(i, "InKill"); + midiInVolume = G_Patch_DEPR_.getMidiValue(i, "InVolume"); + midiInMute = G_Patch_DEPR_.getMidiValue(i, "InMute"); + midiInSolo = G_Patch_DEPR_.getMidiValue(i, "InSolo"); } -void Channel::readPatchMidiOut(int i) +void Channel::readPatchMidiOut_DEPR_(int i) { - midiOutL = G_Patch.getMidiValue(i, "OutL"); - midiOutLplaying = G_Patch.getMidiValue(i, "OutLplaying"); - midiOutLmute = G_Patch.getMidiValue(i, "OutLmute"); - midiOutLsolo = G_Patch.getMidiValue(i, "OutLsolo"); + midiOutL = G_Patch_DEPR_.getMidiValue(i, "OutL"); + midiOutLplaying = G_Patch_DEPR_.getMidiValue(i, "OutLplaying"); + midiOutLmute = G_Patch_DEPR_.getMidiValue(i, "OutLmute"); + midiOutLsolo = G_Patch_DEPR_.getMidiValue(i, "OutLsolo"); } @@ -156,30 +159,119 @@ bool Channel::isPlaying() /* -------------------------------------------------------------------------- */ -void Channel::writePatch(FILE *fp, int i, bool isProject) +int Channel::writePatch(int i, bool isProject) { - fprintf(fp, "chanType%d=%d\n", i, type); - fprintf(fp, "chanIndex%d=%d\n", i, index); - fprintf(fp, "chanColumn%d=%d\n", i, guiChannel->getColumnIndex()); - fprintf(fp, "chanMute%d=%d\n", i, mute); - fprintf(fp, "chanMute_s%d=%d\n", i, mute_s); - fprintf(fp, "chanSolo%d=%d\n", i, solo); - fprintf(fp, "chanvol%d=%f\n", i, volume); - fprintf(fp, "chanPanLeft%d=%f\n", i, panLeft); - fprintf(fp, "chanPanRight%d=%f\n", i, panRight); - - fprintf(fp, "chanMidiIn%d=%u\n", i, midiIn); - fprintf(fp, "chanMidiInKeyPress%d=%u\n", i, midiInKeyPress); - fprintf(fp, "chanMidiInKeyRel%d=%u\n", i, midiInKeyRel); - fprintf(fp, "chanMidiInKill%d=%u\n", i, midiInKill); - fprintf(fp, "chanMidiInVolume%d=%u\n", i, midiInVolume); - fprintf(fp, "chanMidiInMute%d=%u\n", i, midiInMute); - fprintf(fp, "chanMidiInSolo%d=%u\n", i, midiInSolo); - - fprintf(fp, "chanMidiOutL%d=%u\n", i, midiOutL); - fprintf(fp, "chanMidiOutLplaying%d=%u\n", i, midiOutLplaying); - fprintf(fp, "chanMidiOutLmute%d=%u\n", i, midiOutLmute); - fprintf(fp, "chanMidiOutLsolo%d=%u\n", i, midiOutLsolo); + Patch::channel_t pch; + pch.type = type; + pch.key = key; + pch.index = index; + pch.column = guiChannel->getColumnIndex(); + pch.mute = mute; + pch.mute_s = mute_s; + pch.solo = solo; + pch.volume = volume; + pch.panLeft = panLeft; + pch.panRight = panRight; + pch.midiIn = midiIn; + pch.midiInKeyPress = midiInKeyPress; + pch.midiInKeyRel = midiInKeyRel; + pch.midiInKill = midiInKill; + pch.midiInVolume = midiInVolume; + pch.midiInMute = midiInMute; + pch.midiInSolo = midiInSolo; + pch.midiOutL = midiOutL; + pch.midiOutLplaying = midiOutLplaying; + pch.midiOutLmute = midiOutLmute; + pch.midiOutLsolo = midiOutLsolo; + + for (unsigned i=0; ichan == index) { + Patch::action_t pac; + pac.type = action->type; + pac.frame = action->frame; + pac.fValue = action->fValue; + pac.iValue = action->iValue; + pch.actions.add(pac); + } + } + } + +#ifdef WITH_VST + + unsigned numPlugs = G_PluginHost.countPlugins(PluginHost::CHANNEL, this); + for (int i=0; istatus) { + Patch::plugin_t pp; + pp.path = pPlugin->pathfile; + pp.bypass = pPlugin->bypass; + for (int k=0; kgetNumParams(); k++) + pp.params.add(pPlugin->getParam(k)); + pch.plugins.add(pp); + } + } + +#endif + + G_Patch.channels.add(pch); + + return G_Patch.channels.size - 1; +} + + +/* -------------------------------------------------------------------------- */ + + +int Channel::readPatch(const string &path, int i) +{ + int ret = 1; + Patch::channel_t *pch = &G_Patch.channels.at(i); + key = pch->key; + type = pch->type; + index = pch->index; + mute = pch->mute; + mute_s = pch->mute_s; + solo = pch->solo; + volume = pch->volume; + panLeft = pch->panLeft; + panRight = pch->panRight; + midiIn = pch->midiIn; + midiInKeyPress = pch->midiInKeyPress; + midiInKeyRel = pch->midiInKeyRel; + midiInKill = pch->midiInKill; + midiInVolume = pch->midiInVolume; + midiInMute = pch->midiInMute; + midiInSolo = pch->midiInSolo; + midiOutL = pch->midiOutL; + midiOutLplaying = pch->midiOutLplaying; + midiOutLmute = pch->midiOutLmute; + midiOutLsolo = pch->midiOutLsolo; + + for (unsigned k=0; kactions.size; k++) { + Patch::action_t *ac = &pch->actions.at(k); + recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue); + } + +#ifdef WITH_VST + + for (unsigned k=0; kplugins.size; k++) { + Patch::plugin_t *ppl = &pch->plugins.at(k); + Plugin *plugin = G_PluginHost.addPlugin(ppl->path.c_str(), PluginHost::CHANNEL, this); + if (plugin != NULL) { + plugin->bypass = ppl->bypass; + for (unsigned j=0; jparams.size; j++) + plugin->setParam(j, ppl->params.at(j)); + ret &= 1; + } + else + ret &= 0; + } + +#endif + + return ret; } diff --git a/src/core/channel.h b/src/core/channel.h index e346280..0a50284 100644 --- a/src/core/channel.h +++ b/src/core/channel.h @@ -52,6 +52,9 @@ #endif +using std::string; + + class Channel { protected: @@ -73,14 +76,16 @@ public: virtual ~Channel(); /* writePatch - * store values in patch, writing to *fp. */ + * Fill a patch with channel values. Returns the index of the last + * Patch::channel_t added. */ - virtual void writePatch(FILE *fp, int i, bool isProject); + virtual int writePatch(int i, bool isProject); - /* loadByPatch - * load a sample inside a patch. */ + /* readPatch + * Fill channel with data from patch. */ - virtual int loadByPatch(const char *file, int i) = 0; + virtual int readPatch_DEPR_(const char *file, int i) = 0; + virtual int readPatch(const string &basePath, int i); /* process * merge vChannels into buffer, plus plugin processing (if any). */ @@ -206,8 +211,8 @@ public: * read from patch all midi-related parameters such as keypress, mute * and so on. */ - void readPatchMidiIn(int i); - void readPatchMidiOut(int i); + void readPatchMidiIn_DEPR_(int i); + void readPatchMidiOut_DEPR_(int i); /* sendMidiL* * send MIDI lightning events to a physical device. */ diff --git a/src/core/conf.cpp b/src/core/conf.cpp index 0dd258e..06c86da 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -353,7 +353,7 @@ int Conf::write() fprintf(fp, "# --- Giada configuration file --- \n"); fprintf(fp, "header=GIADACFG\n"); - fprintf(fp, "version=%s\n", VERSIONE); + fprintf(fp, "version=%s\n", G_VERSION_STR); fprintf(fp, "logMode=%d\n", logMode); diff --git a/src/core/conf.h b/src/core/conf.h index 9120f2e..0c4a3e1 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -33,7 +33,7 @@ #include #include -#include "dataStorage.h" +#include "dataStorageIni.h" #if defined(__APPLE__) @@ -41,7 +41,7 @@ #endif -class Conf : public DataStorage +class Conf : public DataStorageIni { private: diff --git a/src/core/const.h b/src/core/const.h index d771c40..4cf0af3 100644 --- a/src/core/const.h +++ b/src/core/const.h @@ -26,14 +26,17 @@ * * -------------------------------------------------------------------------- */ + #ifndef CONST_H #define CONST_H /* -- version --------------------------------------------------------------- */ -#define VERSIONE "0.10.2" -#define VERSIONE_STR "Giada" -#define VERSIONE_FLOAT 1.01f +#define G_VERSION_STR "0.11.0" +#define G_APP_NAME "Giada" +#define G_VERSION_MAJOR 0 +#define G_VERSION_MINOR 11 +#define G_VERSION_PATCH 0 #define CONF_FILENAME "giada.conf" @@ -69,6 +72,7 @@ #define MAX_PATCHNAME_LEN 32 #define DB_MIN_SCALE 60.0f #define MAX_VST_EVENTS 32 +#define MIN_COLUMN_WIDTH 140 @@ -121,6 +125,7 @@ #define DEFAULT_BARS 1 #define DEFAULT_QUANTIZE 0 // quantizer off #define DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed +#define DEFAULT_COLUMN_WIDTH 380 @@ -221,12 +226,13 @@ #define WID_KEY_GRABBER -10 -/* -- patch signals --------------------------------------------------------- */ -#define PATCH_UNREADABLE 0 -#define PATCH_INVALID -1 -#define PATCH_OPEN_OK 1 -/** TODO - addo to PATCH_ serie the signals for saving/loading */ +/* -- patch signals --------------------------------------------------------- */ +#define PATCH_UNREADABLE 0x01 +#define PATCH_INVALID 0x02 +#define PATCH_READ_OK 0x04 +#define PATCH_WRONG_PLUGINS 0x08 // currently unused +#define PATCH_WRONG_SAMPLES 0x10 // currently unused @@ -288,4 +294,70 @@ const int MIDI_CHANS[16] = { #define MIDI_SYNC_MTC_M 0x04 #define MIDI_SYNC_MTC_S 0x08 +/* JSON patch keys */ + +#define PATCH_KEY_HEADER "header" +#define PATCH_KEY_VERSION "version" +#define PATCH_KEY_VERSION_MAJOR "version_major" +#define PATCH_KEY_VERSION_MINOR "version_minor" +#define PATCH_KEY_VERSION_PATCH "version_patch" +#define PATCH_KEY_NAME "name" +#define PATCH_KEY_BPM "bpm" +#define PATCH_KEY_BARS "bars" +#define PATCH_KEY_BEATS "beats" +#define PATCH_KEY_QUANTIZE "quantize" +#define PATCH_KEY_MASTER_VOL_IN "master_vol_in" +#define PATCH_KEY_MASTER_VOL_OUT "master_vol_out" +#define PATCH_KEY_METRONOME "metronome" +#define PATCH_KEY_LAST_TAKE_ID "last_take_id" +#define PATCH_KEY_SAMPLERATE "samplerate" +#define PATCH_KEY_COLUMNS "columns" +#define PATCH_KEY_MASTER_OUT_PLUGINS "master_out_plugins" +#define PATCH_KEY_MASTER_IN_PLUGINS "master_in_plugins" +#define PATCH_KEY_CHANNELS "channels" +#define PATCH_KEY_CHANNEL_TYPE "type" +#define PATCH_KEY_CHANNEL_INDEX "index" +#define PATCH_KEY_CHANNEL_COLUMN "column" +#define PATCH_KEY_CHANNEL_MUTE "mute" +#define PATCH_KEY_CHANNEL_MUTE_S "mute_s" +#define PATCH_KEY_CHANNEL_SOLO "solo" +#define PATCH_KEY_CHANNEL_VOLUME "volume" +#define PATCH_KEY_CHANNEL_PAN_LEFT "pan_left" +#define PATCH_KEY_CHANNEL_PAN_RIGHT "pan_right" +#define PATCH_KEY_CHANNEL_MIDI_IN "midi_in" +#define PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS "midi_in_keypress" +#define PATCH_KEY_CHANNEL_MIDI_IN_KEYREL "midi_in_keyrel" +#define PATCH_KEY_CHANNEL_MIDI_IN_KILL "midi_in_kill" +#define PATCH_KEY_CHANNEL_MIDI_IN_VOLUME "midi_in_volume" +#define PATCH_KEY_CHANNEL_MIDI_IN_MUTE "midi_in_mute" +#define PATCH_KEY_CHANNEL_MIDI_IN_SOLO "midi_in_solo" +#define PATCH_KEY_CHANNEL_MIDI_OUT_L "midi_out_l" +#define PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING "midi_out_l_playing" +#define PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE "midi_out_l_mute" +#define PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO "midi_out_l_solo" +#define PATCH_KEY_CHANNEL_SAMPLE_PATH "sample_path" +#define PATCH_KEY_CHANNEL_KEY "key" +#define PATCH_KEY_CHANNEL_MODE "mode" +#define PATCH_KEY_CHANNEL_BEGIN "begin" +#define PATCH_KEY_CHANNEL_END "end" +#define PATCH_KEY_CHANNEL_BOOST "boost" +#define PATCH_KEY_CHANNEL_REC_ACTIVE "rec_active" +#define PATCH_KEY_CHANNEL_PITCH "pitch" +#define PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS "midi_in_read_actions" +#define PATCH_KEY_CHANNEL_MIDI_IN_PITCH "midi_in_pitch" +#define PATCH_KEY_CHANNEL_MIDI_OUT "midi_out" +#define PATCH_KEY_CHANNEL_MIDI_OUT_CHAN "midi_out_chan" +#define PATCH_KEY_CHANNEL_PLUGINS "plugins" +#define PATCH_KEY_CHANNEL_ACTIONS "actions" +#define PATCH_KEY_ACTION_TYPE "type" +#define PATCH_KEY_ACTION_FRAME "frame" +#define PATCH_KEY_ACTION_F_VALUE "f_value" +#define PATCH_KEY_ACTION_I_VALUE "i_value" +#define PATCH_KEY_PLUGIN_PATH "path" +#define PATCH_KEY_PLUGIN_BYPASS "bypass" +#define PATCH_KEY_PLUGIN_PARAMS "params" +#define PATCH_KEY_COLUMN_INDEX "index" +#define PATCH_KEY_COLUMN_WIDTH "width" +#define PATCH_KEY_COLUMN_CHANNELS "channels" + #endif diff --git a/src/core/dataStorage.cpp b/src/core/dataStorageIni.cpp similarity index 91% rename from src/core/dataStorage.cpp rename to src/core/dataStorageIni.cpp index 0cea01f..abf374b 100644 --- a/src/core/dataStorage.cpp +++ b/src/core/dataStorageIni.cpp @@ -2,7 +2,7 @@ * * Giada - Your Hardcore Loopmachine * - * dataStorage + * dataStorageIni * * ----------------------------------------------------------------------------- * @@ -30,12 +30,12 @@ #include #include #include "../utils/log.h" -#include "dataStorage.h" +#include "dataStorageIni.h" #include "const.h" -std::string DataStorage::getValue(const char *in) { - +std::string DataStorageIni::getValue(const char *in) +{ /* on each call reset the pointe to the beginning of the file. Not so * good but necessary if you want to pick up random values from the * file. */ @@ -47,7 +47,7 @@ std::string DataStorage::getValue(const char *in) { char buffer[MAX_LINE_LEN]; if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) { - gLog("[PATCH] get_value error (key=%s)\n", in); + gLog("[DataStorageIni::getValue] key '%s' not found\n", in); return ""; } diff --git a/src/core/dataStorage.h b/src/core/dataStorageIni.h similarity index 88% rename from src/core/dataStorage.h rename to src/core/dataStorageIni.h index 9d54ddf..17b65a9 100644 --- a/src/core/dataStorage.h +++ b/src/core/dataStorageIni.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * - * dataStorage + * dataStorageIni * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,11 +24,11 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ -#ifndef __DATA_STORAGE_H__ -#define __DATA_STORAGE_H__ +#ifndef __DATA_STORAGE_INI_H__ +#define __DATA_STORAGE_INI_H__ #include #include @@ -37,8 +37,8 @@ #define MAX_LINE_LEN 1024 -class DataStorage { - +class DataStorageIni +{ protected: FILE *fp; diff --git a/src/core/dataStorageJson.cpp b/src/core/dataStorageJson.cpp new file mode 100644 index 0000000..d8ffb86 --- /dev/null +++ b/src/core/dataStorageJson.cpp @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * dataStorageIni + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../utils/log.h" +#include "dataStorageJson.h" + + +using std::string; + + +bool DataStorageJson::setString(json_t *jRoot, const char *key, string &output) +{ + json_t *jObject = json_object_get(jRoot, key); + if (!json_is_string(jObject)) { + gLog("[dataStorageJson::setString] key '%s' is not a string!\n", key); + json_decref(jRoot); + return false; + } + output = json_string_value(jObject); + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::setFloat(json_t *jRoot, const char *key, float &output) +{ + json_t *jObject = json_object_get(jRoot, key); + if (!jObject) { + gLog("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key); + output = 0.0f; + return true; + } + if (!json_is_real(jObject)) { + gLog("[dataStorageJson::setFloat] key '%s' is not a float!\n", key); + json_decref(jRoot); + return false; + } + output = json_real_value(jObject); + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::setUint32(json_t *jRoot, const char *key, uint32_t &output) +{ + json_t *jObject = json_object_get(jRoot, key); + if (!jObject) { + gLog("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key); + output = 0; + return true; + } + if (!json_is_integer(jObject)) { + gLog("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key); + json_decref(jRoot); + return false; + } + output = json_integer_value(jObject); + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::setBool(json_t *jRoot, const char *key, bool &output) +{ + json_t *jObject = json_object_get(jRoot, key); + if (!jObject) { + gLog("[dataStorageJson::setBool] key '%s' not found, using default value\n", key); + output = false; + return true; + } + if (!json_is_boolean(jObject)) { + gLog("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key); + json_decref(jRoot); + return false; + } + output = json_boolean_value(jObject); + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::setInt(json_t *jRoot, const char *key, int &output) +{ + return setUint32(jRoot, key, (uint32_t&) output); +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::checkObject(json_t *jRoot, const char *key) +{ + if (!json_is_object(jRoot)) { + gLog("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key); + json_decref(jRoot); + return false; + } + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +bool DataStorageJson::checkArray(json_t *jRoot, const char *key) +{ + if (!json_is_array(jRoot)) { + gLog("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key); + json_decref(jRoot); + return false; + } + return true; +} diff --git a/src/core/dataStorageJson.h b/src/core/dataStorageJson.h new file mode 100644 index 0000000..ad3cdea --- /dev/null +++ b/src/core/dataStorageJson.h @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * dataStorageIni + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 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 __DATA_STORAGE_JSON_H__ +#define __DATA_STORAGE_JSON_H__ + + +#include +#include + + +using std::string; + + +class DataStorageJson +{ +protected: + + json_t *jRoot; + json_error_t jError; + + bool setString(json_t *jRoot, const char *key, string &output); + bool setFloat(json_t *jRoot, const char *key, float &output); + bool setUint32(json_t *jRoot, const char *key, uint32_t &output); + bool setInt(json_t *jRoot, const char *key, int &output); + bool setBool(json_t *jRoot, const char *key, bool &output); + + /* checkObject + check whether the jRoot object is a valid json object {} */ + + bool checkObject(json_t *jRoot, const char *key); + + /* checkArray + check whether the jRoot object is a valid json array [] */ + + bool checkArray(json_t *jRoot, const char *key); +}; + +#endif diff --git a/src/core/init.cpp b/src/core/init.cpp index 1ecbb2d..473ecac 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -38,6 +38,7 @@ #include "wave.h" #include "const.h" #include "mixerHandler.h" +#include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "pluginHost.h" @@ -49,7 +50,8 @@ extern Mixer G_Mixer; extern bool G_audio_status; extern bool G_quit; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; +extern Patch G_Patch; extern Conf G_Conf; extern MidiMapConf G_MidiMap; extern gdMainWindow *mainWin; @@ -62,12 +64,13 @@ extern PluginHost G_PluginHost; void init_prepareParser() { G_Conf.read(); - G_Patch.setDefault(); + G_Patch_DEPR_.setDefault(); + G_Patch.init(); if (!gLog_init(G_Conf.logMode)) gLog("[init] log init failed! Using default stdout\n"); time_t t; time (&t); - gLog("[init] Giada "VERSIONE" - %s", ctime(&t)); + gLog("[init] Giada " G_VERSION_STR " - %s", ctime(&t)); gLog("[init] configuration file ready\n"); } @@ -119,8 +122,8 @@ void init_startGUI(int argc, char **argv) { char win_label[32]; sprintf(win_label, "%s - %s", - VERSIONE_STR, - !strcmp(G_Patch.name, "") ? "(default patch)" : G_Patch.name); + G_APP_NAME, + !strcmp(G_Patch_DEPR_.name, "") ? "(default patch)" : G_Patch_DEPR_.name); mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv); mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH); @@ -196,6 +199,6 @@ void init_shutdown() gLog("[init] Plugin Host cleaned up\n"); #endif - gLog("[init] Giada "VERSIONE" closed\n\n"); + gLog("[init] Giada " G_VERSION_STR " closed\n\n"); gLog_close(); } diff --git a/src/core/midiChannel.cpp b/src/core/midiChannel.cpp index dfb95f8..a890f38 100644 --- a/src/core/midiChannel.cpp +++ b/src/core/midiChannel.cpp @@ -31,11 +31,13 @@ #include "midiChannel.h" #include "channel.h" #include "pluginHost.h" +#include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "kernelMidi.h" +extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; @@ -274,21 +276,21 @@ void MidiChannel::kill(int frame) /* -------------------------------------------------------------------------- */ -int MidiChannel::loadByPatch(const char *f, int i) +int MidiChannel::readPatch_DEPR_(const char *f, int i) { - volume = G_Patch.getVol(i); - index = G_Patch.getIndex(i); - mute = G_Patch.getMute(i); - mute_s = G_Patch.getMute_s(i); - solo = G_Patch.getSolo(i); - panLeft = G_Patch.getPanLeft(i); - panRight = G_Patch.getPanRight(i); + volume = G_Patch_DEPR_.getVol(i); + index = G_Patch_DEPR_.getIndex(i); + mute = G_Patch_DEPR_.getMute(i); + mute_s = G_Patch_DEPR_.getMute_s(i); + solo = G_Patch_DEPR_.getSolo(i); + panLeft = G_Patch_DEPR_.getPanLeft(i); + panRight = G_Patch_DEPR_.getPanRight(i); - midiOut = G_Patch.getMidiValue(i, "Out"); - midiOutChan = G_Patch.getMidiValue(i, "OutChan"); + midiOut = G_Patch_DEPR_.getMidiValue(i, "Out"); + midiOutChan = G_Patch_DEPR_.getMidiValue(i, "OutChan"); - readPatchMidiIn(i); - readPatchMidiOut(i); + readPatchMidiIn_DEPR_(i); + readPatchMidiOut_DEPR_(i); return SAMPLE_LOADED_OK; /// TODO - change name, it's meaningless here } @@ -297,6 +299,22 @@ int MidiChannel::loadByPatch(const char *f, int i) /* -------------------------------------------------------------------------- */ +int MidiChannel::readPatch(const string &basePath, int i) +{ + Channel::readPatch("", i); + + Patch::channel_t *pch = &G_Patch.channels.at(i); + + midiOut = pch->midiOut; + midiOutChan = pch->midiOutChan; + + return SAMPLE_LOADED_OK; /// TODO - change name, it's meaningless here +} + + +/* -------------------------------------------------------------------------- */ + + void MidiChannel::sendMidi(recorder::action *a, int localFrame) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { @@ -339,10 +357,13 @@ void MidiChannel::rewind() /* -------------------------------------------------------------------------- */ -void MidiChannel::writePatch(FILE *fp, int i, bool isProject) +int MidiChannel::writePatch(int i, bool isProject) { - Channel::writePatch(fp, i, isProject); + int pchIndex = Channel::writePatch(i, isProject); + Patch::channel_t *pch = &G_Patch.channels.at(pchIndex); + + pch->midiOut = midiOut; + pch->midiOutChan = midiOutChan; - fprintf(fp, "chanMidiOut%d=%u\n", i, midiOut); - fprintf(fp, "chanMidiOutChan%d=%u\n", i, midiOutChan); + return 0; } diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h index 275081c..cd26ad9 100644 --- a/src/core/midiChannel.h +++ b/src/core/midiChannel.h @@ -50,8 +50,8 @@ #endif -class MidiChannel : public Channel { - +class MidiChannel : public Channel +{ public: MidiChannel(int bufferSize); @@ -60,21 +60,22 @@ public: bool midiOut; // enable midi output uint8_t midiOutChan; // midi output channel - void process (float *buffer); - void start (int frame, bool doQuantize); - void kill (int frame); - void empty (); - void stopBySeq (); - void stop (); - void rewind (); - void setMute (bool internal); - void unsetMute (bool internal); - int loadByPatch(const char *file, int i); - void writePatch (FILE *fp, int i, bool isProject); - void quantize (int index, int localFrame, int globalFrame); - void onZero (int frame); - void onBar (int frame); - void parseAction(recorder::action *a, int localFrame, int globalFrame); + void process (float *buffer); + void start (int frame, bool doQuantize); + void kill (int frame); + void empty (); + void stopBySeq (); + void stop (); + void rewind (); + void setMute (bool internal); + void unsetMute (bool internal); + int readPatch_DEPR_ (const char *file, int i); + int readPatch (const string &basePath, int i); + int writePatch (int i, bool isProject); + void quantize (int index, int localFrame, int globalFrame); + void onZero (int frame); + void onBar (int frame); + void parseAction(recorder::action *a, int localFrame, int globalFrame); /* ---------------------------------------------------------------- */ diff --git a/src/core/midiMapConf.h b/src/core/midiMapConf.h index d56795a..3f397be 100644 --- a/src/core/midiMapConf.h +++ b/src/core/midiMapConf.h @@ -33,7 +33,7 @@ #include #include -#include "dataStorage.h" +#include "dataStorageIni.h" #include "../utils/utils.h" #if defined(__APPLE__) #include @@ -43,7 +43,7 @@ using std::string; -class MidiMapConf : public DataStorage +class MidiMapConf : public DataStorageIni { private: diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index 2930f81..24a9b25 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -35,7 +35,7 @@ #include "wave.h" #include "recorder.h" #include "pluginHost.h" -#include "patch.h" +#include "patch_DEPR_.h" #include "conf.h" #include "mixerHandler.h" #include "channel.h" @@ -45,17 +45,30 @@ extern Mixer G_Mixer; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif -Mixer::Mixer() {} +Mixer::Mixer() + : vChanInput(NULL), + vChanInToOut(NULL) +{ + gLog("[mixer] construct\n"); +} + + +/* -------------------------------------------------------------------------- */ + + Mixer::~Mixer() {} +/* -------------------------------------------------------------------------- */ + + #define TICKSIZE 38 @@ -84,7 +97,8 @@ float Mixer::tick[TICKSIZE] = { /* ------------------------------------------------------------------ */ -void Mixer::init() { +void Mixer::init() +{ quanto = 1; docross = false; rewindWait = false; @@ -138,8 +152,8 @@ void Mixer::init() { /* ------------------------------------------------------------------ */ -Channel *Mixer::addChannel(int type) { - +Channel *Mixer::addChannel(int type) +{ Channel *ch; int bufferSize = kernelAudio::realBufsize*2; @@ -166,8 +180,8 @@ Channel *Mixer::addChannel(int type) { /* ------------------------------------------------------------------ */ -int Mixer::getNewIndex() { - +int Mixer::getNewIndex() +{ /* always skip last channel: it's the last one just added */ if (channels.size == 1) @@ -186,7 +200,8 @@ int Mixer::getNewIndex() { /* ------------------------------------------------------------------ */ -int Mixer::deleteChannel(Channel *ch) { +int Mixer::deleteChannel(Channel *ch) +{ int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&mutex_chans); @@ -205,7 +220,8 @@ int Mixer::deleteChannel(Channel *ch) { /* ------------------------------------------------------------------ */ -Channel *Mixer::getChannelByIndex(int index) { +Channel *Mixer::getChannelByIndex(int index) +{ for (unsigned i=0; iindex == index) return channels.at(i); @@ -217,8 +233,8 @@ Channel *Mixer::getChannelByIndex(int index) { /* ------------------------------------------------------------------ */ -void Mixer::sendMIDIsync() { - +void Mixer::sendMIDIsync() +{ if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { if (actualFrame % (framesPerBeat/24) == 0) kernelMidi::send(MIDI_CLOCK, -1, -1); @@ -283,8 +299,8 @@ void Mixer::sendMIDIsync() { /* ------------------------------------------------------------------ */ -void Mixer::sendMIDIrewind() { - +void Mixer::sendMIDIrewind() +{ midiTCframes = 0; midiTCseconds = 0; midiTCminutes = 0; @@ -308,7 +324,8 @@ void Mixer::sendMIDIrewind() { int Mixer::masterPlay( void *out_buf, void *in_buf, unsigned n_frames, - double streamTime, RtAudioStreamStatus status, void *userData) { + double streamTime, RtAudioStreamStatus status, void *userData) +{ return G_Mixer.__masterPlay(out_buf, in_buf, n_frames); } @@ -316,8 +333,8 @@ int Mixer::masterPlay( /* ------------------------------------------------------------------ */ -int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) { - +int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) +{ if (!ready) return 0; @@ -548,8 +565,8 @@ int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) { /* ------------------------------------------------------------------ */ -void Mixer::updateFrameBars() { - +void Mixer::updateFrameBars() +{ /* seconds ....... total time of play (in seconds) of the whole * sequencer. 60 / bpm == how many seconds lasts one bpm * totalFrames ... number of frames in the whole sequencer, x2 because @@ -587,12 +604,20 @@ void Mixer::updateFrameBars() { /* ------------------------------------------------------------------ */ -int Mixer::close() { +int Mixer::close() +{ running = false; while (channels.size > 0) deleteChannel(channels.at(0)); - free(vChanInput); - free(vChanInToOut); + + if (vChanInput) { + free(vChanInput); + vChanInput = NULL; + } + if (vChanInToOut) { + free(vChanInToOut); + vChanInToOut = NULL; + } return 1; } @@ -600,7 +625,8 @@ int Mixer::close() { /* ------------------------------------------------------------------ */ -bool Mixer::isSilent() { +bool Mixer::isSilent() +{ for (unsigned i=0; istatus == STATUS_PLAY) return false; @@ -611,8 +637,8 @@ bool Mixer::isSilent() { /* ------------------------------------------------------------------ */ -void Mixer::rewind() { - +void Mixer::rewind() +{ actualFrame = 0; actualBeat = 0; @@ -627,8 +653,8 @@ void Mixer::rewind() { /* ------------------------------------------------------------------ */ -void Mixer::updateQuanto() { - +void Mixer::updateQuanto() +{ /* big troubles if frames are odd. */ if (quantize != 0) @@ -641,7 +667,8 @@ void Mixer::updateQuanto() { /* ------------------------------------------------------------------ */ -bool Mixer::hasLogicalSamples() { +bool Mixer::hasLogicalSamples() +{ for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*)channels.at(i))->wave) @@ -654,7 +681,8 @@ bool Mixer::hasLogicalSamples() { /* ------------------------------------------------------------------ */ -bool Mixer::hasEditedSamples() { +bool Mixer::hasEditedSamples() +{ for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*)channels.at(i))->wave) @@ -667,7 +695,8 @@ bool Mixer::hasEditedSamples() { /* ------------------------------------------------------------------ */ -bool Mixer::mergeVirtualInput() { +bool Mixer::mergeVirtualInput() +{ if (vChanInput == NULL) { gLog("[Mixer] virtual input channel not alloc'd\n"); return false; diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp index 427808b..b03b154 100644 --- a/src/core/mixerHandler.cpp +++ b/src/core/mixerHandler.cpp @@ -45,6 +45,7 @@ #include "plugin.h" #include "waveFx.h" #include "conf.h" +#include "patch_DEPR_.h" #include "patch.h" #include "recorder.h" #include "channel.h" @@ -52,12 +53,13 @@ #include "wave.h" -extern Mixer G_Mixer; -extern Patch G_Patch; -extern Conf G_Conf; +extern Mixer G_Mixer; +extern Patch_DEPR_ G_Patch_DEPR_; +extern Patch G_Patch; +extern Conf G_Conf; #ifdef WITH_VST -extern PluginHost G_PluginHost; +extern PluginHost G_PluginHost; #endif @@ -72,17 +74,6 @@ void mh_stopSequencer() /* -------------------------------------------------------------------------- */ -void mh_clear() -{ - G_Mixer.running = false; - while (G_Mixer.channels.size > 0) - G_Mixer.channels.del(0U); // unsigned -} - - -/* -------------------------------------------------------------------------- */ - - bool mh_uniqueSolo(Channel *ch) { int solos = 0; @@ -100,36 +91,63 @@ bool mh_uniqueSolo(Channel *ch) /** TODO - revision needed: mh should not call glue_addChannel */ -void mh_loadPatch(bool isProject, const char *projPath) +void mh_loadPatch_DEPR_(bool isProject, const char *projPath) { G_Mixer.init(); G_Mixer.ready = false; // put it in wait mode - int numChans = G_Patch.getNumChans(); + int numChans = G_Patch_DEPR_.getNumChans(); for (int i=0; ireadPatch_DEPR_(samplePath.c_str(), i); + } - Channel *ch = glue_addChannel(G_Patch.getColumn(i), G_Patch.getType(i)); + G_Mixer.outVol = G_Patch_DEPR_.getOutVol(); + G_Mixer.inVol = G_Patch_DEPR_.getInVol(); + G_Mixer.bpm = G_Patch_DEPR_.getBpm(); + G_Mixer.bars = G_Patch_DEPR_.getBars(); + G_Mixer.beats = G_Patch_DEPR_.getBeats(); + G_Mixer.quantize = G_Patch_DEPR_.getQuantize(); + G_Mixer.metronome = G_Patch_DEPR_.getMetronome(); + G_Patch_DEPR_.lastTakeId = G_Patch_DEPR_.getLastTakeId(); + G_Patch_DEPR_.samplerate = G_Patch_DEPR_.getSamplerate(); - char smpPath[PATH_MAX]; - sprintf(smpPath, "%s%s%s", gDirname(projPath).c_str(), gGetSlash().c_str(), G_Patch.getSamplePath(i).c_str()); + /* rewind and update frames in Mixer (it's vital) */ - ch->loadByPatch(smpPath, i); - } + G_Mixer.rewind(); + G_Mixer.updateFrameBars(); + G_Mixer.ready = true; +} - G_Mixer.outVol = G_Patch.getOutVol(); - G_Mixer.inVol = G_Patch.getInVol(); - G_Mixer.bpm = G_Patch.getBpm(); - G_Mixer.bars = G_Patch.getBars(); - G_Mixer.beats = G_Patch.getBeats(); - G_Mixer.quantize = G_Patch.getQuantize(); - G_Mixer.metronome = G_Patch.getMetronome(); - G_Patch.lastTakeId = G_Patch.getLastTakeId(); - G_Patch.samplerate = G_Patch.getSamplerate(); - /* rewind and update frames in Mixer (it's vital) */ +/* -------------------------------------------------------------------------- */ + + +void mh_readPatch() +{ + G_Mixer.ready = false; + + G_Mixer.outVol = G_Patch.masterVolOut; + G_Mixer.inVol = G_Patch.masterVolIn; + G_Mixer.bpm = G_Patch.bpm; + G_Mixer.bars = G_Patch.bars; + G_Mixer.beats = G_Patch.beats; + G_Mixer.quantize = G_Patch.quantize; + G_Mixer.metronome = G_Patch.metronome; + +#ifdef WITH_VST + + __mh_readPatchPlugins__(&G_Patch.masterInPlugins, PluginHost::MASTER_IN); + __mh_readPatchPlugins__(&G_Patch.masterOutPlugins, PluginHost::MASTER_OUT); + +#endif + + /* rewind and update frames in Mixer (it's essential) */ G_Mixer.rewind(); G_Mixer.updateFrameBars(); + G_Mixer.ready = true; } @@ -174,13 +192,14 @@ SampleChannel *mh_startInputRec() /* increase lastTakeId until the sample name TAKE-[n] is unique */ char name[32]; - sprintf(name, "TAKE-%d", G_Patch.lastTakeId); + sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); while (!mh_uniqueSamplename(chan, name)) { + G_Patch_DEPR_.lastTakeId++; G_Patch.lastTakeId++; - sprintf(name, "TAKE-%d", G_Patch.lastTakeId); + sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); } - chan->allocEmpty(G_Mixer.totalFrames, G_Patch.lastTakeId); + chan->allocEmpty(G_Mixer.totalFrames, G_Patch_DEPR_.lastTakeId); G_Mixer.chanInput = chan; /* start to write from the actualFrame, not the beginning */ @@ -228,3 +247,29 @@ bool mh_uniqueSamplename(SampleChannel *ch, const char *name) } return true; } + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST + +int __mh_readPatchPlugins__(gVector *list, int type) +{ + int ret = 1; + for (unsigned i=0; isize; i++) { + Patch::plugin_t *ppl = &list->at(i); + Plugin *plugin = G_PluginHost.addPlugin(ppl->path.c_str(), type, NULL); + if (plugin != NULL) { + plugin->bypass = ppl->bypass; + for (unsigned j=0; jparams.size; j++) + plugin->setParam(j, ppl->params.at(j)); + ret &= 1; + } + else + ret &= 0; + } + return ret; +} + +#endif diff --git a/src/core/mixerHandler.h b/src/core/mixerHandler.h index f842004..8785e35 100644 --- a/src/core/mixerHandler.h +++ b/src/core/mixerHandler.h @@ -32,6 +32,7 @@ #include "recorder.h" +#include "patch.h" /* stopSequencer @@ -42,11 +43,6 @@ void mh_stopSequencer(); void mh_rewindSequencer(); -/* clear - * stop everything and clear all channels. */ - -void mh_clear(); - /* uniqueSolo * true if ch is the only solo'd channel in mixer. */ @@ -56,7 +52,8 @@ bool mh_uniqueSolo(class Channel *ch); * load a path or a project (if isProject) into Mixer. If isProject, path * must contain the address of the project folder. */ -void mh_loadPatch(bool isProject, const char *projPath=0); +void mh_loadPatch_DEPR_(bool isProject, const char *projPath=0); +void mh_readPatch(); /* startInputRec - record from line in * creates a new empty wave in the first available channels and returns @@ -73,4 +70,10 @@ SampleChannel *mh_stopInputRec(); bool mh_uniqueSamplename(class SampleChannel *ch, const char *name); +#ifdef WITH_VST + +static int __mh_readPatchPlugins__(gVector *list, int type); + +#endif + #endif diff --git a/src/core/patch.cpp b/src/core/patch.cpp index 3613070..5bc84c9 100644 --- a/src/core/patch.cpp +++ b/src/core/patch.cpp @@ -33,6 +33,7 @@ #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/elems/ge_keyboard.h" #include "patch.h" +#include "const.h" #include "init.h" #include "recorder.h" #include "conf.h" @@ -50,28 +51,15 @@ extern PluginHost G_PluginHost; extern gdMainWindow *mainWin; -int Patch::open(const char *file) +void Patch::init() { - fp = fopen(file, "r"); - if (fp == NULL) - return PATCH_UNREADABLE; - - if (getValue("header") != "GIADAPTC") - return PATCH_INVALID; - - version = atof(getValue("versionf").c_str()); - gLog("[patch] open patch version %f\n", version); - - return PATCH_OPEN_OK; -} - - -/* -------------------------------------------------------------------------- */ - - -void Patch::setDefault() -{ - name[0] = '\0'; + columns.clear(); + channels.clear(); +#ifdef WITH_VST + masterInPlugins.clear(); + masterOutPlugins.clear(); +#endif + header = "GIADAPTC"; lastTakeId = 0; samplerate = DEFAULT_SAMPLERATE; } @@ -80,660 +68,417 @@ void Patch::setDefault() /* -------------------------------------------------------------------------- */ -int Patch::close() -{ - return fclose(fp); -} - - -/* -------------------------------------------------------------------------- */ - - -void Patch::getName() -{ - std::string out = getValue("patchname"); - strncpy(name, out.c_str(), MAX_PATCHNAME_LEN); -} - - -/* -------------------------------------------------------------------------- */ - - -std::string Patch::getSamplePath(int c) -{ - char tmp[16]; - sprintf(tmp, "samplepath%d", c); - return getValue(tmp); -} - - -/* -------------------------------------------------------------------------- */ - - -float Patch::getPitch(int c) +int Patch::write(const string &file) { - char tmp[16]; - sprintf(tmp, "chanPitch%d", c); - float out = atof(getValue(tmp).c_str()); - if (out > 2.0f || out < 0.1f) - return 1.0f; - return out; -} - + jRoot = json_object(); -/* -------------------------------------------------------------------------- */ - - -int Patch::getNumChans() -{ - if (version == 0.0) // backward compatibility with version < 0.6.1 - return 32; - return atoi(getValue("channels").c_str()); -} - - -/* -------------------------------------------------------------------------- */ - - -int Patch::getNumColumns() -{ - return atoi(getValue("columns").c_str()); -} - - -/* -------------------------------------------------------------------------- */ - - -int Patch::getColumn(int c) -{ - if (version == 0.0) // backward compatibility with version < 0.6.1 - return 0; - char tmp[16]; - sprintf(tmp, "chanColumn%d", c); - return atoi(getValue(tmp).c_str()); -} - - -/* -------------------------------------------------------------------------- */ - - -int Patch::getIndex(int c) -{ - if (version == 0.0) // backward compatibility with version < 0.6.1 - return c; + writeCommons(jRoot); + writeColumns(jRoot, &columns); + writeChannels(jRoot, &channels); +#ifdef WITH_VST + writePlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS); + writePlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS); +#endif - char tmp[16]; - sprintf(tmp, "chanIndex%d", c); - return atoi(getValue(tmp).c_str()); + if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) { + gLog("[Patch::write] unable to write patch file!\n"); + return 0; + } + return 1; } /* -------------------------------------------------------------------------- */ -float Patch::getVol(int c) +int Patch::read(const string &file) { - char tmp[16]; - sprintf(tmp, "chanvol%d", c); - float out = atof(getValue(tmp).c_str()); - if (out > 1.0f || out < 0.0f) - return DEFAULT_VOL; - return out; -} - - -/* -------------------------------------------------------------------------- */ + jRoot = json_load_file(file.c_str(), 0, &jError); + if (!jRoot) { + gLog("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text); + return PATCH_UNREADABLE; + } + if (!checkObject(jRoot, "root element")) + return PATCH_INVALID; -int Patch::getMode(int c) -{ - char tmp[16]; - sprintf(tmp, "chanmode%d", c); - int out = atoi(getValue(tmp).c_str()); - if (out & (LOOP_ANY | SINGLE_ANY)) - return out; - return DEFAULT_CHANMODE; -} + init(); + /* TODO json_decref also when PATCH_INVALID */ -/* -------------------------------------------------------------------------- */ - - -int Patch::getMute(int c) -{ - char tmp[16]; - sprintf(tmp, "chanMute%d", c); - return atoi(getValue(tmp).c_str()); -} - + if (!readCommons(jRoot)) return setInvalid(); + if (!readColumns(jRoot)) return setInvalid(); + if (!readChannels(jRoot)) return setInvalid(); +#ifdef WITH_VST + if (!readPlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS)) return setInvalid(); + if (!readPlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS)) return setInvalid(); +#endif -/* -------------------------------------------------------------------------- */ + json_decref(jRoot); + sanitize(); -int Patch::getMute_s(int c) -{ - char tmp[16]; - sprintf(tmp, "chanMute_s%d", c); - return atoi(getValue(tmp).c_str()); + return PATCH_READ_OK; } - /* -------------------------------------------------------------------------- */ +#ifdef WITH_VST -int Patch::getSolo(int c) +void Patch::writePlugins(json_t *jContainer, gVector *plugins, const char *key) { - char tmp[16]; - sprintf(tmp, "chanSolo%d", c); - return atoi(getValue(tmp).c_str()); -} - - -/* -------------------------------------------------------------------------- */ + json_t *jPlugins = json_array(); + for (unsigned j=0; jsize; j++) { + json_t *jPlugin = json_object(); + plugin_t plugin = plugins->at(j); + json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH, json_string(plugin.path.c_str())); + json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass)); + json_array_append_new(jPlugins, jPlugin); + /* plugin params */ -int Patch::getType(int c) -{ - char tmp[16]; - sprintf(tmp, "chanType%d", c); - int out = atoi(getValue(tmp).c_str()); - if (out == 0) - return CHANNEL_SAMPLE; - return out; + json_t *jPluginParams = json_array(); + for (unsigned z=0; z *columns) { - char tmp[16]; - sprintf(tmp, "chanend%d", c); - - /* if chanEnd doesn't exist, it returns an atoi(empty string) == 0. - * good in theory, a disaster in practice. */ - - std::string val = getValue(tmp); - if (val == "") - return size; - - unsigned out = atoi(val.c_str()); - if (out <= 0 || out > size) - return size; - return out; + json_t *jColumns = json_array(); + for (unsigned i=0; isize; i++) { + json_t *jColumn = json_object(); + column_t column = columns->at(i); + json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index)); + json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width)); + json_array_append_new(jColumns, jColumn); + } + json_object_set_new(jContainer, PATCH_KEY_COLUMNS, jColumns); } /* -------------------------------------------------------------------------- */ -float Patch::getBoost(int c) +void Patch::writeActions(json_t *jContainer, gVector *actions) { - char tmp[16]; - sprintf(tmp, "chanBoost%d", c); - float out = atof(getValue(tmp).c_str()); - if (out < 1.0f) - return DEFAULT_BOOST; - return out; + json_t *jActions = json_array(); + for (unsigned k=0; ksize; k++) { + json_t *jAction = json_object(); + action_t action = actions->at(k); + json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE, json_integer(action.type)); + json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME, json_integer(action.frame)); + json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue)); + json_object_set_new(jAction, PATCH_KEY_ACTION_I_VALUE, json_integer(action.iValue)); + json_array_append_new(jActions, jAction); + } + json_object_set_new(jContainer, PATCH_KEY_CHANNEL_ACTIONS, jActions); } /* -------------------------------------------------------------------------- */ -float Patch::getPanLeft(int c) +void Patch::writeCommons(json_t *jContainer) { - char tmp[16]; - sprintf(tmp, "chanPanLeft%d", c); - std::string val = getValue(tmp); - if (val == "") - return 1.0f; - - float out = atof(val.c_str()); - if (out < 0.0f || out > 1.0f) - return 1.0f; - return out; + json_object_set_new(jContainer, PATCH_KEY_HEADER, json_string(header.c_str())); + json_object_set_new(jContainer, PATCH_KEY_VERSION, json_string(version.c_str())); + json_object_set_new(jContainer, PATCH_KEY_VERSION_MAJOR, json_integer(versionMajor)); + json_object_set_new(jContainer, PATCH_KEY_VERSION_MINOR, json_integer(versionMinor)); + json_object_set_new(jContainer, PATCH_KEY_VERSION_PATCH, json_integer(versionPatch)); + json_object_set_new(jContainer, PATCH_KEY_NAME, json_string(name.c_str())); + json_object_set_new(jContainer, PATCH_KEY_BPM, json_real(bpm)); + json_object_set_new(jContainer, PATCH_KEY_BARS, json_integer(bars)); + json_object_set_new(jContainer, PATCH_KEY_BEATS, json_integer(beats)); + json_object_set_new(jContainer, PATCH_KEY_QUANTIZE, json_integer(quantize)); + json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_IN, json_real(masterVolIn)); + json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_OUT, json_real(masterVolOut)); + json_object_set_new(jContainer, PATCH_KEY_METRONOME, json_integer(metronome)); + json_object_set_new(jContainer, PATCH_KEY_LAST_TAKE_ID, json_integer(lastTakeId)); + json_object_set_new(jContainer, PATCH_KEY_SAMPLERATE, json_integer(samplerate)); } /* -------------------------------------------------------------------------- */ -int Patch::getKey(int c) +void Patch::writeChannels(json_t *jContainer, gVector *channels) { - if (version == 0.0) // backward compatibility with version < 0.6.1 - return 0; - char tmp[16]; - sprintf(tmp, "chanKey%d", c); - return atoi(getValue(tmp).c_str()); -} + json_t *jChannels = json_array(); + for (unsigned i=0; isize; i++) { + json_t *jChannel = json_object(); + channel_t channel = channels->at(i); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE, json_integer(channel.type)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX, json_integer(channel.index)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN, json_integer(channel.column)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE, json_integer(channel.mute)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S, json_integer(channel.mute_s)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SOLO, json_integer(channel.solo)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_VOLUME, json_real(channel.volume)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN_LEFT, json_real(channel.panLeft)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN_RIGHT, json_real(channel.panRight)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN, json_boolean(channel.midiIn)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, json_integer(channel.midiInKeyPress)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, json_integer(channel.midiInKeyRel)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, json_integer(channel.midiInKill)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, json_integer(channel.midiInVolume)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, json_integer(channel.midiInMute)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, json_integer(channel.midiInSolo)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L, json_boolean(channel.midiOutL)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING, json_integer(channel.midiOutLplaying)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE, json_integer(channel.midiOutLmute)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO, json_integer(channel.midiOutLsolo)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH, json_string(channel.samplePath.c_str())); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_KEY, json_integer(channel.key)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MODE, json_integer(channel.mode)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BEGIN, json_integer(channel.begin)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_END, json_integer(channel.end)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BOOST, json_real(channel.boost)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, json_integer(channel.recActive)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PITCH, json_real(channel.pitch)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, json_integer(channel.midiInReadActions)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, json_integer(channel.midiInPitch)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, json_integer(channel.midiOut)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, json_integer(channel.midiOutChan)); + json_array_append_new(jChannels, jChannel); + writeActions(jChannel, &channel.actions); -/* -------------------------------------------------------------------------- */ +#ifdef WITH_VST + writePlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS); -float Patch::getPanRight(int c) -{ - char tmp[16]; - sprintf(tmp, "chanPanRight%d", c); - std::string val = getValue(tmp); - if (val == "") - return 1.0f; - - float out = atof(val.c_str()); - if (out < 0.0f || out > 1.0f) - return 1.0f; - return out; +#endif + } + json_object_set_new(jContainer, PATCH_KEY_CHANNELS, jChannels); } /* -------------------------------------------------------------------------- */ -bool Patch::getRecActive(int c) +bool Patch::readCommons(json_t *jContainer) { - char tmp[16]; - sprintf(tmp, "chanRecActive%d", c); - return atoi(getValue(tmp).c_str()); + if (!setString(jContainer, PATCH_KEY_HEADER, header)) return 0; + if (!setString(jContainer, PATCH_KEY_VERSION, version)) return 0; + if (!setInt (jContainer, PATCH_KEY_VERSION_MAJOR, versionMajor)) return 0; + if (!setInt (jContainer, PATCH_KEY_VERSION_MINOR, versionMinor)) return 0; + if (!setInt (jContainer, PATCH_KEY_VERSION_PATCH, versionPatch)) return 0; + if (!setString(jContainer, PATCH_KEY_NAME, name)) return 0; + if (!setFloat (jContainer, PATCH_KEY_BPM, bpm)) return 0; + if (!setInt (jContainer, PATCH_KEY_BARS, bars)) return 0; + if (!setInt (jContainer, PATCH_KEY_BEATS, beats)) return 0; + if (!setInt (jContainer, PATCH_KEY_QUANTIZE, quantize)) return 0; + if (!setFloat (jContainer, PATCH_KEY_MASTER_VOL_IN, masterVolIn)) return 0; + if (!setFloat (jContainer, PATCH_KEY_MASTER_VOL_OUT, masterVolOut)) return 0; + if (!setInt (jContainer, PATCH_KEY_METRONOME, metronome)) return 0; + if (!setInt (jContainer, PATCH_KEY_LAST_TAKE_ID, lastTakeId)) return 0; + if (!setInt (jContainer, PATCH_KEY_SAMPLERATE, samplerate)) return 0; + return 1; } /* -------------------------------------------------------------------------- */ -float Patch::getOutVol() +bool Patch::readColumns(json_t *jContainer) { - return atof(getValue("outVol").c_str()); -} + json_t *jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS); + if (!checkArray(jColumns, PATCH_KEY_COLUMNS)) + return 0; + size_t columnIndex; + json_t *jColumn; + json_array_foreach(jColumns, columnIndex, jColumn) { -/* -------------------------------------------------------------------------- */ + string columnIndexStr = "column " + gItoa(columnIndex); + if (!checkObject(jColumn, columnIndexStr.c_str())) + return 0; + column_t column; + if (!setInt(jColumn, PATCH_KEY_COLUMN_INDEX, column.index)) return 0; + if (!setInt(jColumn, PATCH_KEY_COLUMN_WIDTH, column.width)) return 0; -float Patch::getInVol() -{ - return atof(getValue("inVol").c_str()); + columns.add(column); + } + return 1; } /* -------------------------------------------------------------------------- */ -float Patch::getBpm() +bool Patch::readChannels(json_t *jContainer) { - float out = atof(getValue("bpm").c_str()); - if (out < 20.0f || out > 999.0f) - return DEFAULT_BPM; - return out; -} + json_t *jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS); + if (!checkArray(jChannels, PATCH_KEY_CHANNELS)) + return 0; + size_t channelIndex; + json_t *jChannel; + json_array_foreach(jChannels, channelIndex, jChannel) { -/* -------------------------------------------------------------------------- */ - - -int Patch::getBars() -{ - int out = atoi(getValue("bars").c_str()); - if (out <= 0 || out > 32) - return DEFAULT_BARS; - return out; -} + string channelIndexStr = "channel " + gItoa(channelIndex); + if (!checkObject(jChannel, channelIndexStr.c_str())) + return 0; + channel_t channel; -/* -------------------------------------------------------------------------- */ + if (!setInt (jChannel, PATCH_KEY_CHANNEL_TYPE, channel.type)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_INDEX, channel.index)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_COLUMN, channel.column)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_MUTE, channel.mute)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_MUTE_S, channel.mute_s)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_SOLO, channel.solo)) return 0; + if (!setFloat (jChannel, PATCH_KEY_CHANNEL_VOLUME, channel.volume)) return 0; + if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PAN_LEFT, channel.panRight)) return 0; + if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PAN_RIGHT, channel.panLeft)) return 0; + if (!setBool (jChannel, PATCH_KEY_CHANNEL_MIDI_IN, channel.midiIn)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, channel.midiInKeyPress)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, channel.midiInKeyRel)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, channel.midiInKill)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, channel.midiInVolume)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, channel.midiInMute)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, channel.midiInSolo)) return 0; + if (!setBool (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L, channel.midiOutL)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING, channel.midiOutLplaying)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE, channel.midiOutLmute)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO, channel.midiOutLsolo)) return 0; + if (!setString(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH, channel.samplePath)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_KEY, channel.key)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_MODE, channel.mode)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_BEGIN, channel.begin)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_END, channel.end)) return 0; + if (!setFloat (jChannel, PATCH_KEY_CHANNEL_BOOST, channel.boost)) return 0; + if (!setInt (jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, channel.recActive)) return 0; + if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PITCH, channel.pitch)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, channel.midiInReadActions)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, channel.midiInPitch)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, channel.midiOut)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, channel.midiOutChan)) return 0; + readActions(jChannel, &channel); -int Patch::getBeats() -{ - int out = atoi(getValue("beats").c_str()); - if (out <= 0 || out > 32) - return DEFAULT_BEATS; - return out; +#ifdef WITH_VST + readPlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS); +#endif + channels.add(channel); + } + return 1; } /* -------------------------------------------------------------------------- */ -int Patch::getQuantize() +bool Patch::readActions(json_t *jContainer, channel_t *channel) { - int out = atoi(getValue("quantize").c_str()); - if (out < 0 || out > 8) - return DEFAULT_QUANTIZE; - return out; -} + json_t *jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS); + if (!checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS)) + return 0; + size_t actionIndex; + json_t *jAction; + json_array_foreach(jActions, actionIndex, jAction) { -/* -------------------------------------------------------------------------- */ - + if (!checkObject(jAction, "")) // TODO pass actionIndex as string + return 0; -bool Patch::getMetronome() -{ - return atoi(getValue("metronome").c_str()); + action_t action; + if (!setInt (jAction, PATCH_KEY_ACTION_TYPE, action.type)) return 0; + if (!setInt (jAction, PATCH_KEY_ACTION_FRAME, action.frame)) return 0; + if (!setFloat (jAction, PATCH_KEY_ACTION_F_VALUE, action.fValue)) return 0; + if (!setUint32(jAction, PATCH_KEY_ACTION_I_VALUE, action.iValue)) return 0; + channel->actions.add(action); + } + return 1; } /* -------------------------------------------------------------------------- */ -int Patch::getLastTakeId() -{ - return atoi(getValue("lastTakeId").c_str()); -} - - -/* -------------------------------------------------------------------------- */ - +#ifdef WITH_VST -int Patch::getSamplerate() +bool Patch::readPlugins(json_t *jContainer, gVector *container, const char *key) { - int out = atoi(getValue("samplerate").c_str()); - if (out <= 0) - return DEFAULT_SAMPLERATE; - return out; -} - + json_t *jPlugins = json_object_get(jContainer, key); + if (!checkArray(jPlugins, key)) + return 0; -/* -------------------------------------------------------------------------- */ + size_t pluginIndex; + json_t *jPlugin; + json_array_foreach(jPlugins, pluginIndex, jPlugin) { + if (!checkObject(jPlugin, "")) // TODO pass pluginIndex as string + return 0; -uint32_t Patch::getMidiValue(int i, const char *c) -{ - char tmp[32]; - sprintf(tmp, "chanMidi%s%d", c, i); - return strtoul(getValue(tmp).c_str(), NULL, 10); -} + plugin_t plugin; + if (!setString (jPlugin, PATCH_KEY_PLUGIN_PATH, plugin.path)) return 0; + if (!setBool (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0; + /* read plugin params */ -/* -------------------------------------------------------------------------- */ + json_t *jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS); + if (!checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0; + size_t paramIndex; + json_t *jParam; + json_array_foreach(jParams, paramIndex, jParam) + plugin.params.add(json_real_value(jParam)); -int Patch::readRecs() -{ - gLog("[patch] Reading recs...\n"); - - unsigned numrecs = atoi(getValue("numrecs").c_str()); - - for (unsigned i=0; istatus & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) { - if (version < 0.83f) - recorder::rec(ch->index, type, frame, iValue_fix, fValue); - else - recorder::rec(ch->index, type, frame, iValue, fValue); - } - } - } - return 1; + container->add(plugin); + } + return 1; } - -/* -------------------------------------------------------------------------- */ - - -#ifdef WITH_VST -int Patch::readPlugins() -{ - gLog("[patch] Reading plugins...\n"); - - int globalOut = 1; - - /* master plugins */ - - globalOut &= readMasterPlugins(PluginHost::MASTER_IN); - globalOut &= readMasterPlugins(PluginHost::MASTER_OUT); - - /* channel plugins */ - - for (unsigned i=0; iindex); - int np = atoi(getValue(tmp).c_str()); - - for (int j=0; jindex, j); - int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), PluginHost::CHANNEL, ch); - if (out != 0) { - sprintf(tmp, "chan%d_p%dnumParams", ch->index, j); - 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->bypass = atoi(getValue(tmp).c_str()); - for (int k=0; kindex, j, k); - float pval = atof(getValue(tmp).c_str()); - pPlugin->setParam(k, pval); - } - } - globalOut &= out; - } - } - return globalOut; -} #endif /* -------------------------------------------------------------------------- */ -int Patch::write(const char *file, const char *name, bool project) +void Patch::sanitize() { - fp = fopen(file, "w"); - if (fp == NULL) - return 0; - - fprintf(fp, "# --- Giada patch file --- \n"); - fprintf(fp, "header=GIADAPTC\n"); - fprintf(fp, "version=%s\n", VERSIONE); - fprintf(fp, "versionf=%f\n", VERSIONE_FLOAT); - fprintf(fp, "patchname=%s\n", name); - fprintf(fp, "bpm=%f\n", G_Mixer.bpm); - fprintf(fp, "bars=%d\n", G_Mixer.bars); - fprintf(fp, "beats=%d\n", G_Mixer.beats); - fprintf(fp, "quantize=%d\n", G_Mixer.quantize); - fprintf(fp, "outVol=%f\n", G_Mixer.outVol); - fprintf(fp, "inVol=%f\n", G_Mixer.inVol); - fprintf(fp, "metronome=%d\n", G_Mixer.metronome); - fprintf(fp, "lastTakeId=%d\n", lastTakeId); - fprintf(fp, "samplerate=%d\n", G_Conf.samplerate); // original samplerate when the patch was saved - fprintf(fp, "channels=%d\n", G_Mixer.channels.size); - fprintf(fp, "columns=%d\n", mainWin->keyboard->getTotalColumns()); - - for (unsigned i=0; iwritePatch(fp, i, project); - } - - /* writing recs. Warning: channel index is not mixer.channels.at(chan), - * but mixer.channels.at(chan)->index! */ - - fprintf(fp, "# --- actions --- \n"); - fprintf(fp, "numrecs=%d\n", recorder::global.size); - for (unsigned i=0; ichan, - recorder::global.at(i).at(k)->type, - recorder::global.at(i).at(k)->fValue, - recorder::global.at(i).at(k)->iValue); - } - } + bpm = bpm < 20.0f || bpm > 999.0f ? DEFAULT_BPM : bpm; + bars = bars <= 0 || bars > 32 ? DEFAULT_BARS : bars; + beats = beats <= 0 || beats > 32 ? DEFAULT_BEATS : beats; + quantize = quantize < 0 || quantize > 8 ? DEFAULT_QUANTIZE : quantize; + masterVolIn = masterVolIn < 0.0f || masterVolIn > 1.0f ? DEFAULT_VOL : masterVolIn; + masterVolOut = masterVolOut < 0.0f || masterVolOut > 1.0f ? DEFAULT_VOL : masterVolOut; + samplerate = samplerate <= 0 ? DEFAULT_SAMPLERATE : samplerate; -#ifdef WITH_VST + for (unsigned i=0; iindex = col->index < 0 ? 0 : col->index; + col->width = col->width < MIN_COLUMN_WIDTH ? MIN_COLUMN_WIDTH : col->width; + } - /* writing master VST parameters */ - - writeMasterPlugins(PluginHost::MASTER_IN); - writeMasterPlugins(PluginHost::MASTER_OUT); - - /* writing VST parameters, channels. chan%d is mixer::channels.at(%d)->index, - * not mixer::chanels.at(%d)! */ - - int numPlugs; - int numParams; - Plugin *pPlugin; - - fprintf(fp, "# --- VST / channels --- \n"); - for (unsigned i=0; iindex, numPlugs); - - for (int j=0; jstatus) { - gLog("[patch] Plugin %d is in a bad status, skip writing params\n", i); - continue; - } - fprintf(fp, "chan%d_p%dpathfile=%s\n", ch->index, j, pPlugin->pathfile); - fprintf(fp, "chan%d_p%dbypass=%d\n", ch->index, j, pPlugin->bypass); - numParams = pPlugin->getNumParams(); - fprintf(fp, "chan%d_p%dnumParams=%d\n", ch->index, j, numParams); - - for (int k=0; kindex, j, k, pPlugin->getParam(k)); - } - } - -#endif - - fclose(fp); - return 1; + for (unsigned i=0; ivolume = ch->volume < 0.0f || ch->volume > 1.0f ? DEFAULT_VOL : ch->volume; + ch->panLeft = ch->panLeft < 0.0f || ch->panLeft > 1.0f ? 1.0f : ch->panLeft; + ch->panRight = ch->panRight < 0.0f || ch->panRight > 1.0f ? 1.0f : ch->panRight; + ch->boost = ch->boost < 1.0f ? DEFAULT_BOOST : ch->boost; + ch->pitch = ch->pitch < 0.1f || ch->pitch > 4.0f ? gDEFAULT_PITCH : ch->pitch; + } } /* -------------------------------------------------------------------------- */ -#ifdef WITH_VST -int Patch::readMasterPlugins(int type) +int Patch::setInvalid() { - int nmp; - char chr; - int res = 1; - - if (type == PluginHost::MASTER_IN) { - chr = 'I'; - nmp = atoi(getValue("masterIPlugins").c_str()); - } - else { - chr = 'O'; - nmp = atoi(getValue("masterOPlugins").c_str()); - } - - for (int i=0; ibypass = atoi(getValue(tmp).c_str()); - sprintf(tmp, "master%c_p%dnumParams", chr, i); - int nparam = atoi(getValue(tmp).c_str()); - for (int j=0; jsetParam(j, pval); - } - } - res &= out; - } - - return res; + json_decref(jRoot); + return PATCH_INVALID; } - - -/* -------------------------------------------------------------------------- */ - - -void Patch::writeMasterPlugins(int type) -{ - char chr; - - if (type == PluginHost::MASTER_IN) { - fprintf(fp, "# --- VST / master in --- \n"); - chr = 'I'; - } - else { - fprintf(fp, "# --- VST / master out --- \n"); - chr = 'O'; - } - - int nmp = G_PluginHost.countPlugins(type); - fprintf(fp, "master%cPlugins=%d\n", chr, nmp); - - for (int i=0; istatus) { - gLog("[patch] Plugin %d is in a bad status, skip writing params\n", i); - continue; - } - - fprintf(fp, "master%c_p%dpathfile=%s\n", chr, i, pPlugin->pathfile); - fprintf(fp, "master%c_p%dbypass=%d\n", chr, i, pPlugin->bypass); - int numParams = pPlugin->getNumParams(); - fprintf(fp, "master%c_p%dnumParams=%d\n", chr, i, numParams); - - for (int j=0; jgetParam(j)); - } -} - -#endif diff --git a/src/core/patch.h b/src/core/patch.h index e431b85..5d07f0c 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -30,66 +30,155 @@ #ifndef __PATCH_H__ #define __PATCH_H__ -#include + #include #include -#include "dataStorage.h" +#include "../utils/utils.h" +#include "dataStorageJson.h" #include "const.h" -class Patch : public DataStorage { +using std::string; -private: - int readMasterPlugins(int type); - void writeMasterPlugins(int type); +class Patch : public DataStorageJson +{ public: - char name[MAX_PATCHNAME_LEN]; - float version; - int lastTakeId; - int samplerate; - - int open(const char *file); - void setDefault(); - int close(); - - void getName (); - int getNumChans (); - int getNumColumns (); - std::string getSamplePath (int i); - float getVol (int i); - int getMode (int i); - int getMute (int i); - int getMute_s (int i); - int getSolo (int i); - int getBegin (int i); - int getEnd (int i, unsigned sampleSize); - float getBoost (int i); - float getPanLeft (int i); - float getPanRight (int i); - float getPitch (int i); - bool getRecActive (int i); - int getColumn (int i); - int getIndex (int i); - int getType (int i); - int getKey (int i); - uint32_t getMidiValue (int i, const char *c); - float getOutVol (); - float getInVol (); - float getBpm (); - int getBars (); - int getBeats (); - int getQuantize (); - bool getMetronome (); - int getLastTakeId (); - int getSamplerate (); - - int write(const char *file, const char *name, bool isProject); - int readRecs(); + struct action_t + { + int type; + int frame; + float fValue; + uint32_t iValue; + }; + +#ifdef WITH_VST + struct plugin_t + { + string path; + bool bypass; + gVector params; + }; +#endif + + struct channel_t + { + int type; + int index; + int column; + int mute; + int mute_s; + int solo; + float volume; + float panLeft; + float panRight; + bool midiIn; + uint32_t midiInKeyPress; + uint32_t midiInKeyRel; + uint32_t midiInKill; + uint32_t midiInVolume; + uint32_t midiInMute; + uint32_t midiInSolo; + bool midiOutL; + uint32_t midiOutLplaying; + uint32_t midiOutLmute; + uint32_t midiOutLsolo; + // sample channel + string samplePath; + int key; + int mode; + int begin; + int end; + float boost; + int recActive; + float pitch; + uint32_t midiInReadActions; + uint32_t midiInPitch; + // midi channel + uint32_t midiOut; + uint32_t midiOutChan; + + gVector actions; + +#ifdef WITH_VST + gVector plugins; +#endif + }; + + struct column_t + { + int index; + int width; + gVector channels; + }; + + string header; + string version; + int versionMajor; + int versionMinor; + int versionPatch; + string name; + float bpm; + int bars; + int beats; + int quantize; + float masterVolIn; + float masterVolOut; + int metronome; + int lastTakeId; + int samplerate; // original samplerate when the patch was saved + + gVector columns; + gVector channels; + +#ifdef WITH_VST + gVector masterInPlugins; + gVector masterOutPlugins; +#endif + + /* init + * Init Patch with default values. */ + + void init(); + + /* read/write + * Read/write patch to/from file. */ + + int write(const string &file); + int read (const string &file); + +private: + + /* sanitize + * Internal sanity check. */ + + void sanitize(); + + /* setInvalid + * Helper function used to return invalid status while reading. */ + + int setInvalid(); + + /* readers */ + + bool readCommons (json_t *jContainer); + bool readChannels(json_t *jContainer); +#ifdef WITH_VST + bool readPlugins (json_t *jContainer, gVector *container, const char* key); +#endif + bool readActions (json_t *jContainer, channel_t *channel); + bool readColumns (json_t *jContainer); + + /* writers */ + + void writeCommons (json_t *jContainer); + void writeChannels(json_t *jContainer, gVector *channels); #ifdef WITH_VST - int readPlugins(); + void writePlugins (json_t *jContainer, gVector *plugins, const char* key); #endif + void writeActions (json_t *jContainer, gVector *actions); + void writeColumns (json_t *jContainer, gVector *columns); }; #endif diff --git a/src/core/patch_DEPR_.cpp b/src/core/patch_DEPR_.cpp new file mode 100644 index 0000000..0113591 --- /dev/null +++ b/src/core/patch_DEPR_.cpp @@ -0,0 +1,614 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * patch + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include "../utils/log.h" +#include "../utils/utils.h" +#include "../gui/dialogs/gd_mainWindow.h" +#include "../gui/elems/ge_keyboard.h" +#include "patch_DEPR_.h" +#include "init.h" +#include "recorder.h" +#include "conf.h" +#include "pluginHost.h" +#include "wave.h" +#include "mixer.h" +#include "channel.h" + + +extern Mixer G_Mixer; +extern Conf G_Conf; +#ifdef WITH_VST +extern PluginHost G_PluginHost; +#endif +extern gdMainWindow *mainWin; + + +int Patch_DEPR_::open(const char *file) +{ + fp = fopen(file, "r"); + if (fp == NULL) + return PATCH_UNREADABLE; + + if (getValue("header") != "GIADAPTC") + return PATCH_INVALID; + + version = atof(getValue("versionf").c_str()); + gLog("[patch_DEPR_] open patch version %f\n", version); + + return PATCH_READ_OK; +} + + +/* -------------------------------------------------------------------------- */ + + +void Patch_DEPR_::setDefault() +{ + name[0] = '\0'; + lastTakeId = 0; + samplerate = DEFAULT_SAMPLERATE; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::close() +{ + return fclose(fp); +} + + +/* -------------------------------------------------------------------------- */ + + +void Patch_DEPR_::getName() +{ + std::string out = getValue("patchname"); + strncpy(name, out.c_str(), MAX_PATCHNAME_LEN); +} + + +/* -------------------------------------------------------------------------- */ + + +std::string Patch_DEPR_::getSamplePath(int c) +{ + char tmp[16]; + sprintf(tmp, "samplepath%d", c); + return getValue(tmp); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getPitch(int c) +{ + char tmp[16]; + sprintf(tmp, "chanPitch%d", c); + float out = atof(getValue(tmp).c_str()); + if (out > 2.0f || out < 0.1f) + return 1.0f; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getNumChans() +{ + if (version == 0.0) // backward compatibility with version < 0.6.1 + return 32; + return atoi(getValue("channels").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getNumColumns() +{ + return atoi(getValue("columns").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getColumn(int c) +{ + if (version == 0.0) // backward compatibility with version < 0.6.1 + return 0; + char tmp[16]; + sprintf(tmp, "chanColumn%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getIndex(int c) +{ + if (version == 0.0) // backward compatibility with version < 0.6.1 + return c; + + char tmp[16]; + sprintf(tmp, "chanIndex%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getVol(int c) +{ + char tmp[16]; + sprintf(tmp, "chanvol%d", c); + float out = atof(getValue(tmp).c_str()); + if (out > 1.0f || out < 0.0f) + return DEFAULT_VOL; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getMode(int c) +{ + char tmp[16]; + sprintf(tmp, "chanmode%d", c); + int out = atoi(getValue(tmp).c_str()); + if (out & (LOOP_ANY | SINGLE_ANY)) + return out; + return DEFAULT_CHANMODE; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getMute(int c) +{ + char tmp[16]; + sprintf(tmp, "chanMute%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getMute_s(int c) +{ + char tmp[16]; + sprintf(tmp, "chanMute_s%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getSolo(int c) +{ + char tmp[16]; + sprintf(tmp, "chanSolo%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getType(int c) +{ + char tmp[16]; + sprintf(tmp, "chanType%d", c); + int out = atoi(getValue(tmp).c_str()); + if (out == 0) + return CHANNEL_SAMPLE; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getBegin(int c) +{ + char tmp[16]; + if (version < 0.73f) + sprintf(tmp, "chanstart%d", c); + else + sprintf(tmp, "chanBegin%d", c); + int out = atoi(getValue(tmp).c_str()); + if (out < 0) + return 0; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getEnd(int c, unsigned size) +{ + char tmp[16]; + sprintf(tmp, "chanend%d", c); + + /* if chanEnd doesn't exist, it returns an atoi(empty string) == 0. + * good in theory, a disaster in practice. */ + + std::string val = getValue(tmp); + if (val == "") + return size; + + unsigned out = atoi(val.c_str()); + if (out <= 0 || out > size) + return size; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getBoost(int c) +{ + char tmp[16]; + sprintf(tmp, "chanBoost%d", c); + float out = atof(getValue(tmp).c_str()); + if (out < 1.0f) + return DEFAULT_BOOST; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getPanLeft(int c) +{ + char tmp[16]; + sprintf(tmp, "chanPanLeft%d", c); + std::string val = getValue(tmp); + if (val == "") + return 1.0f; + + float out = atof(val.c_str()); + if (out < 0.0f || out > 1.0f) + return 1.0f; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getKey(int c) +{ + if (version == 0.0) // backward compatibility with version < 0.6.1 + return 0; + char tmp[16]; + sprintf(tmp, "chanKey%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getPanRight(int c) +{ + char tmp[16]; + sprintf(tmp, "chanPanRight%d", c); + std::string val = getValue(tmp); + if (val == "") + return 1.0f; + + float out = atof(val.c_str()); + if (out < 0.0f || out > 1.0f) + return 1.0f; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +bool Patch_DEPR_::getRecActive(int c) +{ + char tmp[16]; + sprintf(tmp, "chanRecActive%d", c); + return atoi(getValue(tmp).c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getOutVol() +{ + return atof(getValue("outVol").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getInVol() +{ + return atof(getValue("inVol").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +float Patch_DEPR_::getBpm() +{ + float out = atof(getValue("bpm").c_str()); + if (out < 20.0f || out > 999.0f) + return DEFAULT_BPM; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getBars() +{ + int out = atoi(getValue("bars").c_str()); + if (out <= 0 || out > 32) + return DEFAULT_BARS; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getBeats() +{ + int out = atoi(getValue("beats").c_str()); + if (out <= 0 || out > 32) + return DEFAULT_BEATS; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getQuantize() +{ + int out = atoi(getValue("quantize").c_str()); + if (out < 0 || out > 8) + return DEFAULT_QUANTIZE; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +bool Patch_DEPR_::getMetronome() +{ + return atoi(getValue("metronome").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getLastTakeId() +{ + return atoi(getValue("lastTakeId").c_str()); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::getSamplerate() +{ + int out = atoi(getValue("samplerate").c_str()); + if (out <= 0) + return DEFAULT_SAMPLERATE; + return out; +} + + +/* -------------------------------------------------------------------------- */ + + +uint32_t Patch_DEPR_::getMidiValue(int i, const char *c) +{ + char tmp[32]; + sprintf(tmp, "chanMidi%s%d", c, i); + return strtoul(getValue(tmp).c_str(), NULL, 10); +} + + +/* -------------------------------------------------------------------------- */ + + +int Patch_DEPR_::readRecs() +{ + gLog("[patch_DEPR_] Reading recs...\n"); + + unsigned numrecs = atoi(getValue("numrecs").c_str()); + + for (unsigned i=0; istatus & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) { + if (version < 0.83f) + recorder::rec(ch->index, type, frame, iValue_fix, fValue); + else + recorder::rec(ch->index, type, frame, iValue, fValue); + } + } + } + return 1; +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST +int Patch_DEPR_::readPlugins() +{ + gLog("[patch_DEPR_] Reading plugins...\n"); + + int globalOut = 1; + + /* master plugins */ + + globalOut &= readMasterPlugins(PluginHost::MASTER_IN); + globalOut &= readMasterPlugins(PluginHost::MASTER_OUT); + + /* channel plugins */ + + for (unsigned i=0; iindex); + int np = atoi(getValue(tmp).c_str()); + + for (int j=0; jindex, j); + Plugin *plugin = G_PluginHost.addPlugin(getValue(tmp).c_str(), PluginHost::CHANNEL, ch); + if (plugin != NULL) { + sprintf(tmp, "chan%d_p%dnumParams", ch->index, j); + 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->bypass = atoi(getValue(tmp).c_str()); + for (int k=0; kindex, j, k); + float pval = atof(getValue(tmp).c_str()); + pPlugin->setParam(k, pval); + } + globalOut &= 1; + } + else + globalOut &= 0; + } + } + return globalOut; +} +#endif + + +/* -------------------------------------------------------------------------- */ + +#ifdef WITH_VST + +int Patch_DEPR_::readMasterPlugins(int type) +{ + int nmp; + char chr; + int res = 1; + + if (type == PluginHost::MASTER_IN) { + chr = 'I'; + nmp = atoi(getValue("masterIPlugins").c_str()); + } + else { + chr = 'O'; + nmp = atoi(getValue("masterOPlugins").c_str()); + } + + for (int i=0; ibypass = atoi(getValue(tmp).c_str()); + sprintf(tmp, "master%c_p%dnumParams", chr, i); + int nparam = atoi(getValue(tmp).c_str()); + for (int j=0; jsetParam(j, pval); + } + res &= 1; + } + else + res &= 0; + } + + return res; +} + +#endif diff --git a/src/core/patch_DEPR_.h b/src/core/patch_DEPR_.h new file mode 100644 index 0000000..9c08bd8 --- /dev/null +++ b/src/core/patch_DEPR_.h @@ -0,0 +1,94 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * patch + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 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 __PATCH_DEPR_H__ +#define __PATCH_DEPR_H__ + +#include +#include +#include +#include "dataStorageIni.h" +#include "const.h" + + +class Patch_DEPR_ : public DataStorageIni +{ +private: + + int readMasterPlugins(int type); + +public: + + char name[MAX_PATCHNAME_LEN]; + float version; + int lastTakeId; + int samplerate; + + int open(const char *file); + void setDefault(); + int close(); + + void getName (); + int getNumChans (); + int getNumColumns (); + std::string getSamplePath (int i); + float getVol (int i); + int getMode (int i); + int getMute (int i); + int getMute_s (int i); + int getSolo (int i); + int getBegin (int i); + int getEnd (int i, unsigned sampleSize); + float getBoost (int i); + float getPanLeft (int i); + float getPanRight (int i); + float getPitch (int i); + bool getRecActive (int i); + int getColumn (int i); + int getIndex (int i); + int getType (int i); + int getKey (int i); + uint32_t getMidiValue (int i, const char *c); + float getOutVol (); + float getInVol (); + float getBpm (); + int getBars (); + int getBeats (); + int getQuantize (); + bool getMetronome (); + int getLastTakeId (); + int getSamplerate (); + + int readRecs(); +#ifdef WITH_VST + int readPlugins(); +#endif +}; + +#endif diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp index 6202050..6b02b89 100644 --- a/src/core/pluginHost.cpp +++ b/src/core/pluginHost.cpp @@ -253,7 +253,7 @@ VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 i /* 33 - product version */ case audioMasterGetVendorVersion: - return (int) VERSIONE_FLOAT * 100; + return (int) (G_VERSION_MAJOR * 100) + (G_VERSION_MINOR * 10) + G_VERSION_PATCH; /* 37 - Plugin asks Host if it implements the feature text. */ @@ -308,7 +308,7 @@ VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 i /* ------------------------------------------------------------------ */ -int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { +Plugin *PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { Plugin *p = new Plugin(); bool success = true; @@ -327,7 +327,7 @@ int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { if (!success) { pStack->add(p); - return 0; + return NULL; } /* otherwise let's try to initialize it. */ @@ -338,7 +338,7 @@ int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { if (!p->init(&PluginHost::HostCallback)) { delete p; - return 0; + return NULL; } /* plugin setup */ @@ -364,7 +364,7 @@ int PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { p->resume(); - return 1; + return p; } } diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h index 58907ad..71d4d84 100644 --- a/src/core/pluginHost.h +++ b/src/core/pluginHost.h @@ -90,7 +90,11 @@ public: static VstIntPtr VSTCALLBACK HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); VstIntPtr gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); - int addPlugin(const char *fname, int stackType, class Channel *ch=NULL); + /* addPlugin + * Add a new plugin to the stack. If the operation goes well, returns a pointer + * to the newly inserted plugin. */ + + Plugin *addPlugin(const char *fname, int stackType, class Channel *ch=NULL); void processEvents(float *buffer, class Channel *ch); diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index 73d9b38..58324f2 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -36,7 +36,7 @@ #include "kernelAudio.h" #include "pluginHost.h" #include "kernelMidi.h" -#include "patch.h" +#include "patch_DEPR_.h" #include "conf.h" #include "channel.h" #include "sampleChannel.h" @@ -49,9 +49,9 @@ extern PluginHost G_PluginHost; #endif -extern Mixer G_Mixer; -extern Patch f_patch; -extern Conf G_Conf; +extern Mixer G_Mixer; +extern Patch_DEPR_ f_patch; +extern Conf G_Conf; namespace recorder diff --git a/src/core/sampleChannel.cpp b/src/core/sampleChannel.cpp index 168b581..ad5866f 100644 --- a/src/core/sampleChannel.cpp +++ b/src/core/sampleChannel.cpp @@ -30,6 +30,7 @@ #include #include "../utils/log.h" #include "sampleChannel.h" +#include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "wave.h" @@ -39,6 +40,7 @@ #include "kernelMidi.h" +extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; @@ -824,32 +826,32 @@ int SampleChannel::load(const char *file) /* -------------------------------------------------------------------------- */ -int SampleChannel::loadByPatch(const char *f, int i) +int SampleChannel::readPatch_DEPR_(const char *f, int i) { int res = load(f); - volume = G_Patch.getVol(i); - key = G_Patch.getKey(i); - index = G_Patch.getIndex(i); - mode = G_Patch.getMode(i); - mute = G_Patch.getMute(i); - mute_s = G_Patch.getMute_s(i); - solo = G_Patch.getSolo(i); - boost = G_Patch.getBoost(i); - panLeft = G_Patch.getPanLeft(i); - panRight = G_Patch.getPanRight(i); - readActions = G_Patch.getRecActive(i); + volume = G_Patch_DEPR_.getVol(i); + key = G_Patch_DEPR_.getKey(i); + index = G_Patch_DEPR_.getIndex(i); + mode = G_Patch_DEPR_.getMode(i); + mute = G_Patch_DEPR_.getMute(i); + mute_s = G_Patch_DEPR_.getMute_s(i); + solo = G_Patch_DEPR_.getSolo(i); + boost = G_Patch_DEPR_.getBoost(i); + panLeft = G_Patch_DEPR_.getPanLeft(i); + panRight = G_Patch_DEPR_.getPanRight(i); + readActions = G_Patch_DEPR_.getRecActive(i); recStatus = readActions ? REC_READING : REC_STOPPED; - readPatchMidiIn(i); - midiInReadActions = G_Patch.getMidiValue(i, "InReadActions"); - midiInPitch = G_Patch.getMidiValue(i, "InPitch"); - readPatchMidiOut(i); + readPatchMidiIn_DEPR_(i); + midiInReadActions = G_Patch_DEPR_.getMidiValue(i, "InReadActions"); + midiInPitch = G_Patch_DEPR_.getMidiValue(i, "InPitch"); + readPatchMidiOut_DEPR_(i); if (res == SAMPLE_LOADED_OK) { - setBegin(G_Patch.getBegin(i)); - setEnd (G_Patch.getEnd(i, wave->size)); - setPitch(G_Patch.getPitch(i)); + setBegin(G_Patch_DEPR_.getBegin(i)); + setEnd (G_Patch_DEPR_.getEnd(i, wave->size)); + setPitch(G_Patch_DEPR_.getPitch(i)); } else { // volume = DEFAULT_VOL; @@ -872,6 +874,44 @@ int SampleChannel::loadByPatch(const char *f, int i) /* -------------------------------------------------------------------------- */ +int SampleChannel::readPatch(const string &basePath, int i) +{ + /* load channel's data first: if the sample is missing or wrong, the channel + * is not completely blank. */ + + Channel::readPatch("", i); + + Patch::channel_t *pch = &G_Patch.channels.at(i); + + mode = pch->mode; + boost = pch->boost; + readActions = pch->recActive; + recStatus = readActions ? REC_READING : REC_STOPPED; + midiInReadActions = pch->midiInReadActions; + midiInPitch = pch->midiInPitch; + + int res = load((basePath + pch->samplePath).c_str()); + if (res == SAMPLE_LOADED_OK) { + setBegin(pch->begin); + setEnd (pch->end); + setPitch(pch->pitch); + } + else { + if (res == SAMPLE_LEFT_EMPTY) + status = STATUS_EMPTY; + else + if (res == SAMPLE_READ_ERROR) + status = STATUS_MISSING; + sendMidiLplay(); // FIXME - why sending MIDI lightning if sample status is wrong? + } + + return res; +} + + +/* -------------------------------------------------------------------------- */ + + bool SampleChannel::canInputRec() { return wave == NULL; @@ -953,29 +993,29 @@ void SampleChannel::start(int frame, bool doQuantize) /* -------------------------------------------------------------------------- */ -void SampleChannel::writePatch(FILE *fp, int i, bool isProject) +int SampleChannel::writePatch(int i, bool isProject) { - Channel::writePatch(fp, i, isProject); + int pchIndex = Channel::writePatch(i, isProject); + Patch::channel_t *pch = &G_Patch.channels.at(pchIndex); - std::string path; if (wave != NULL) { - path = wave->pathfile; + pch->samplePath = wave->pathfile; if (isProject) - path = gBasename(path); // make it portable + pch->samplePath = gBasename(wave->pathfile); // make it portable } - - fprintf(fp, "samplepath%d=%s\n", i, path.c_str()); - fprintf(fp, "chanKey%d=%d\n", i, key); - //fprintf(fp, "columnIndex%d=%d\n", i, index); - fprintf(fp, "chanmode%d=%d\n", i, mode); - fprintf(fp, "chanBegin%d=%d\n", i, begin); - fprintf(fp, "chanend%d=%d\n", i, end); - fprintf(fp, "chanBoost%d=%f\n", i, boost); - fprintf(fp, "chanRecActive%d=%d\n", i, readActions); - fprintf(fp, "chanPitch%d=%f\n", i, pitch); - - fprintf(fp, "chanMidiInReadActions%d=%u\n", i, midiInReadActions); - fprintf(fp, "chanMidiInPitch%d=%u\n", i, midiInPitch); + else + pch->samplePath = ""; + + pch->mode = mode; + pch->begin = begin; + pch->end = end; + pch->boost = boost; + pch->recActive = readActions; + pch->pitch = pitch; + pch->midiInReadActions = midiInReadActions; + pch->midiInPitch = midiInPitch; + + return 0; } diff --git a/src/core/sampleChannel.h b/src/core/sampleChannel.h index 736063a..228a1b5 100644 --- a/src/core/sampleChannel.h +++ b/src/core/sampleChannel.h @@ -83,24 +83,25 @@ public: SampleChannel(int bufferSize); ~SampleChannel(); - void clear (); - void process (float *buffer); - void start (int frame, bool doQuantize); - void kill (int frame); - void empty (); - void stopBySeq (); - void stop (); - void rewind (); - void setMute (bool internal); - void unsetMute (bool internal); - void reset (int frame); - int load (const char *file); - int loadByPatch(const char *file, int i); - void writePatch (FILE *fp, int i, bool isProject); - void quantize (int index, int localFrame, int globalFrame); - void onZero (int frame); - void onBar (int frame); - void parseAction(recorder::action *a, int localFrame, int globalFrame); + void clear (); + void process (float *buffer); + void start (int frame, bool doQuantize); + void kill (int frame); + void empty (); + void stopBySeq (); + void stop (); + void rewind (); + void setMute (bool internal); + void unsetMute (bool internal); + void reset (int frame); + int load (const char *file); + int readPatch_DEPR_ (const char *file, int i); + int readPatch (const string &basePath, int i); + int writePatch (int i, bool isProject); + void quantize (int index, int localFrame, int globalFrame); + void onZero (int frame); + void onBar (int frame); + void parseAction(recorder::action *a, int localFrame, int globalFrame); /* fade methods * prepare channel for fade, mixer will take care of the process diff --git a/src/glue/glue.cpp b/src/glue/glue.cpp index c2ec2c5..d7db772 100644 --- a/src/glue/glue.cpp +++ b/src/glue/glue.cpp @@ -53,14 +53,14 @@ #include "../core/sampleChannel.h" #include "../core/midiChannel.h" #include "../core/kernelMidi.h" -#include "../core/patch.h" +#include "../core/patch_DEPR_.h" #include "../core/conf.h" #include "glue.h" extern gdMainWindow *mainWin; extern Mixer G_Mixer; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; extern bool G_audio_status; #ifdef WITH_VST @@ -106,110 +106,6 @@ Channel *glue_addChannel(int column, int type) /* -------------------------------------------------------------------------- */ -int glue_loadPatch(const char *fname, const char *fpath, gProgress *status, bool isProject) -{ - /* update browser's status bar with % 0.1 */ - - status->show(); - status->value(0.1f); - //Fl::check(); - Fl::wait(0); - - /* is it a valid patch? */ - - int res = G_Patch.open(fname); - if (res != PATCH_OPEN_OK) - return res; - - /* close all other windows. This prevents segfault if plugin windows - * GUI are on. */ - - if (res) - gu_closeAllSubwindows(); - - /* reset the system. False(1): don't update the gui right now. False(2): do - * not create empty columns. */ - - glue_resetToInitState(false, false); - - status->value(0.2f); // progress status: % 0.2 - //Fl::check(); - Fl::wait(0); - - /* mixerHandler will update the samples inside Mixer */ - - mh_loadPatch(isProject, fname); - - /* take the patch name and update the main window's title */ - - G_Patch.getName(); - gu_update_win_label(G_Patch.name); - - status->value(0.4f); // progress status: 0.4 - //Fl::check(); - Fl::wait(0); - - G_Patch.readRecs(); - status->value(0.6f); // progress status: 0.6 - //Fl::check(); - Fl::wait(0); - -#ifdef WITH_VST - int resPlugins = G_Patch.readPlugins(); - status->value(0.8f); // progress status: 0.8 - //Fl::check(); - Fl::wait(0); -#endif - - /* this one is vital: let recorder recompute the actions' positions if - * the current samplerate != patch samplerate */ - - recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate); - - /* update gui */ - - gu_updateControls(); - - status->value(1.0f); // progress status: 1.0 (done) - //Fl::check(); - Fl::wait(0); - - /* save patchPath by taking the last dir of the broswer, in order to - * reuse it the next time */ - - G_Conf.setPath(G_Conf.patchPath, fpath); - - gLog("[glue] patch %s loaded\n", fname); - -#ifdef WITH_VST - if (resPlugins != 1) - gdAlert("Some VST plugins were not loaded successfully."); -#endif - - return res; -} - - -/* -------------------------------------------------------------------------- */ - - -int glue_savePatch(const char *fullpath, const char *name, bool isProject) -{ - if (G_Patch.write(fullpath, name, isProject) == 1) { - strcpy(G_Patch.name, name); - G_Patch.name[strlen(name)] = '\0'; - gu_update_win_label(name); - gLog("[glue] patch saved as %s\n", fullpath); - return 1; - } - else - return 0; -} - - -/* -------------------------------------------------------------------------- */ - - void glue_deleteChannel(Channel *ch) { int index = ch->index; @@ -596,23 +492,20 @@ void glue_clearAllRecs() void glue_resetToInitState(bool resetGui, bool createColumns) { - G_Mixer.ready = false; - - mh_clear(); - mainWin->keyboard->clear(); - if (createColumns) - mainWin->keyboard->init(); - recorder::init(); - G_Patch.setDefault(); + G_Patch_DEPR_.setDefault(); + G_Mixer.close(); G_Mixer.init(); + recorder::init(); #ifdef WITH_VST G_PluginHost.freeAllStacks(); #endif + mainWin->keyboard->clear(); + if (createColumns) + mainWin->keyboard->init(); + if (resetGui) gu_updateControls(); - - G_Mixer.ready = true; } @@ -976,55 +869,6 @@ int glue_stopInputRec(bool gui) /* -------------------------------------------------------------------------- */ -int glue_saveProject(const char *folderPath, const char *projName) -{ - if (gIsProject(folderPath)) { - gLog("[glue] the project folder already exists\n"); - // don't exit - } - else if (!gMkdir(folderPath)) { - gLog("[glue] unable to make project directory!\n"); - return 0; - } - - /* copy all samples inside the folder. Takes and logical ones are saved - * via glue_saveSample() */ - - for (unsigned i=0; itype == CHANNEL_SAMPLE) { - - SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); - - if (ch->wave == NULL) - continue; - - /* update the new samplePath: everything now comes from the - * project folder (folderPath) */ - - char samplePath[PATH_MAX]; - sprintf(samplePath, "%s%s%s.%s", folderPath, gGetSlash().c_str(), ch->wave->basename().c_str(), ch->wave->extension().c_str()); - - /* remove any existing file */ - - if (gFileExists(samplePath)) - remove(samplePath); - if (ch->save(samplePath)) - ch->wave->pathfile = samplePath; - } - } - - char gptcPath[PATH_MAX]; - sprintf(gptcPath, "%s%s%s.gptc", folderPath, gGetSlash().c_str(), gStripExt(projName).c_str()); - glue_savePatch(gptcPath, projName, true); // true == it's a project - - return 1; -} - - -/* -------------------------------------------------------------------------- */ - - void glue_keyPress(Channel *ch, bool ctrl, bool shift) { if (ch->type == CHANNEL_SAMPLE) diff --git a/src/glue/glue.h b/src/glue/glue.h index d018a6c..8f085de 100644 --- a/src/glue/glue.h +++ b/src/glue/glue.h @@ -49,10 +49,6 @@ void glue_deleteChannel(class Channel *ch); void glue_freeChannel(class Channel *ch); -/** FIXME - nobody will call these via MIDI/keyb/mouse! */ -int glue_loadPatch(const char *fname, const char *fpath, class gProgress *status, bool isProject); -int glue_savePatch(const char *fullpath, const char *name, bool isProject); - /* keyPress / keyRelease * handle the key pressure, either via mouse/keyboard or MIDI. If gui * is true it means that the event comes from the main window (mouse, @@ -156,10 +152,6 @@ void glue_setMute(class Channel *ch, bool gui=true); void glue_setSoloOn (class Channel *ch, bool gui=true); void glue_setSoloOff(class Channel *ch, bool gui=true); -/** FIXME - nobody will call this via MIDI/keyb/mouse! */ -int glue_saveProject(const char *folderPath, const char *projName); - - /* beatsDivide/Multiply * shrinks or enlarges the number of beats by 2. */ diff --git a/src/glue/storage.cpp b/src/glue/storage.cpp new file mode 100644 index 0000000..5837227 --- /dev/null +++ b/src/glue/storage.cpp @@ -0,0 +1,382 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 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 "../gui/elems/ge_column.h" +#include "../gui/elems/ge_keyboard.h" +#include "../gui/dialogs/gd_mainWindow.h" +#include "../gui/dialogs/gd_warnings.h" +#include "../core/mixer.h" +#include "../core/mixerHandler.h" +#include "../core/channel.h" +#include "../core/pluginHost.h" +#include "../core/conf.h" +#include "../core/patch.h" +#include "../core/patch_DEPR_.h" // TODO - remove, used only for DEPR calls +#include "../core/sampleChannel.h" +#include "../core/midiChannel.h" +#include "../core/wave.h" +#include "../utils/gui_utils.h" +#include "glue.h" // TODO - remove, used only for DEPR calls +#include "storage.h" + + +using std::string; + + +extern gdMainWindow *mainWin; +extern Mixer G_Mixer; +extern Patch G_Patch; +extern Conf G_Conf; +extern Patch_DEPR_ G_Patch_DEPR_; // TODO - remove, used only for DEPR calls +#ifdef WITH_VST +extern PluginHost G_PluginHost; +#endif + + +int glue_savePatch(const string &fullPath, const string &name, bool isProject) +{ + G_Patch.init(); + + __glue_fillPatchGlobals__(name); + __glue_fillPatchChannels__(isProject); + __glue_fillPatchColumns__(); + + if (G_Patch.write(fullPath)) { + gu_update_win_label(name.c_str()); + gLog("[glue] patch saved as %s\n", fullPath.c_str()); + return 1; + } + return 0; +} + + +/* -------------------------------------------------------------------------- */ + + +int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProject) +{ + /* try to load the new JSON-based patch. If it fails, fall back to deprecated + * one. */ + + 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(); + } + + int res = G_Patch.read(fileToLoad); + + 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); + } + if (res != PATCH_READ_OK) + return res; + + /* close all other windows. This prevents segfault if plugin + * windows GUIs are on. */ + + gu_closeAllSubwindows(); + + /* reset the system. False(1): don't update the gui right now. False(2): do + * not create empty columns. */ + + glue_resetToInitState(false, false); + + __setProgressBar__(status, 0.1f); + + /* Add common stuff, columns and channels. Also increment the progress bar + * by 0.8 / total_channels steps. */ + + float steps = 0.8 / G_Patch.channels.size; + for (unsigned i=0; ikeyboard->addColumn(col->width); + for (unsigned k=0; kindex) { + Channel *ch = glue_addChannel(G_Patch.channels.at(k).column, G_Patch.channels.at(k).type); + ch->readPatch(basePath, k); + } + __setProgressBar__(status, steps); + } + } + + /* fill Mixer */ + + mh_readPatch(); + + /* let recorder recompute the actions' positions if the current + * samplerate != patch samplerate */ + + recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate); + + /* save patchPath by taking the last dir of the broswer, in order to + * reuse it the next time */ + + G_Conf.setPath(G_Conf.patchPath, gDirname(fullPath.c_str()).c_str()); + + /* refresh GUI */ + + gu_updateControls(); + gu_update_win_label(G_Patch.name.c_str()); + + __setProgressBar__(status, 1.0f); + + gLog("[glue] patch loaded successfully\n"); + + return res; +} + + +/* -------------------------------------------------------------------------- */ + + +int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *status, bool isProject) +{ + /* update browser's status bar with % 0.1 */ + + status->show(); + status->value(0.1f); + //Fl::check(); + Fl::wait(0); + + /* is it a valid patch? */ + + int res = G_Patch_DEPR_.open(fpath); + if (res != PATCH_READ_OK) + return res; + + /* close all other windows. This prevents segfault if plugin windows + * GUI are on. */ + + if (res) + gu_closeAllSubwindows(); + + /* reset the system. False(1): don't update the gui right now. False(2): do + * not create empty columns. */ + + glue_resetToInitState(false, false); + + status->value(0.2f); // progress status: % 0.2 + //Fl::check(); + Fl::wait(0); + + /* mixerHandler will update the samples inside Mixer */ + + mh_loadPatch_DEPR_(isProject, gDirname(fpath).c_str()); + + /* take the patch name and update the main window's title */ + + G_Patch_DEPR_.getName(); + gu_update_win_label(G_Patch_DEPR_.name); + + status->value(0.4f); // progress status: 0.4 + //Fl::check(); + Fl::wait(0); + + G_Patch_DEPR_.readRecs(); + status->value(0.6f); // progress status: 0.6 + //Fl::check(); + Fl::wait(0); + +#ifdef WITH_VST + int resPlugins = G_Patch_DEPR_.readPlugins(); + status->value(0.8f); // progress status: 0.8 + //Fl::check(); + Fl::wait(0); +#endif + + /* this one is vital: let recorder recompute the actions' positions if + * the current samplerate != patch samplerate */ + + recorder::updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate); + + /* update gui */ + + gu_updateControls(); + + status->value(1.0f); // progress status: 1.0 (done) + //Fl::check(); + Fl::wait(0); + + /* save patchPath by taking the last dir of the broswer, in order to + * reuse it the next time */ + + G_Conf.setPath(G_Conf.patchPath, gDirname(fpath).c_str()); + + gLog("[glue] patch %s loaded\n", fname); + +#ifdef WITH_VST + if (resPlugins != 1) + gdAlert("Some VST plugins were not loaded successfully."); +#endif + + return res; +} + + +/* -------------------------------------------------------------------------- */ + + +void __glue_fillPatchGlobals__(const string &name) +{ + G_Patch.version = G_VERSION_STR; + G_Patch.versionMajor = G_VERSION_MAJOR; + G_Patch.versionMinor = G_VERSION_MINOR; + G_Patch.versionPatch = G_VERSION_PATCH; + G_Patch.name = name; + G_Patch.bpm = G_Mixer.bpm; + G_Patch.bars = G_Mixer.bars; + G_Patch.beats = G_Mixer.beats; + G_Patch.quantize = G_Mixer.quantize; + G_Patch.masterVolIn = G_Mixer.inVol; + G_Patch.masterVolOut = G_Mixer.outVol; + G_Patch.metronome = G_Mixer.metronome; + +#ifdef WITH_VST + + __glue_fillPatchGlobalsPlugins__(&G_PluginHost.masterIn, &G_Patch.masterInPlugins); + __glue_fillPatchGlobalsPlugins__(&G_PluginHost.masterOut, &G_Patch.masterOutPlugins); + +#endif +} + + +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST + +void __glue_fillPatchGlobalsPlugins__(gVector *host, gVector *patch) +{ + for (unsigned i=0; isize; i++) { + Plugin *pl = host->at(i); + Patch::plugin_t ppl; + ppl.path = pl->pathfile; + ppl.bypass = pl->bypass; + int numParams = pl->getNumParams(); + for (unsigned k=0; kgetParam(k)); + patch->add(ppl); + } +} + +#endif + + +/* -------------------------------------------------------------------------- */ + + +void __glue_fillPatchChannels__(bool isProject) +{ + for (unsigned i=0; iwritePatch(i, isProject); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void __glue_fillPatchColumns__() +{ + for (unsigned i=0; ikeyboard->getTotalColumns(); i++) { + gColumn *gCol = mainWin->keyboard->getColumn(i); + Patch::column_t pCol; + pCol.index = gCol->getIndex(); + pCol.width = gCol->w(); + for (unsigned k=0; kcountChannels(); k++) { + Channel *colChannel = gCol->getChannel(k); + for (unsigned j=0; jindex); + break; + } + } + } + G_Patch.columns.add(pCol); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void __setProgressBar__(class gProgress *status, float v) +{ + status->value(status->value() + v); + //Fl::check(); + Fl::wait(0); +} + + +/* -------------------------------------------------------------------------- */ + + +int glue_saveProject(const string &folderPath, const string &projName) +{ + if (!gDirExists(folderPath.c_str()) && !gMkdir(folderPath.c_str())) { + gLog("[glue] unable to make project directory!\n"); + return 0; + } + + /* copy all samples inside the folder. Takes and logical ones are saved + * via glue_saveSample() */ + + for (unsigned i=0; itype == CHANNEL_MIDI) + continue; + + SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); + + if (ch->wave == NULL) + continue; + + /* 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(); + + if (gFileExists(samplePath.c_str())) + remove(samplePath.c_str()); + if (ch->save(samplePath.c_str())) + ch->wave->pathfile = samplePath; + } + + string gptcPath = folderPath + gGetSlash() + gStripExt(projName.c_str()) + ".gptc"; + glue_savePatch(gptcPath, projName, true); // true == it's a project + + return 1; +} diff --git a/src/glue/storage.h b/src/glue/storage.h new file mode 100644 index 0000000..23aee4e --- /dev/null +++ b/src/glue/storage.h @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GLUE_STORAGE_H +#define GLUE_STORAGE_H + + +#include "../core/patch.h" + + +using std::string; + + +int glue_loadPatch (const string &fullPath, class gProgress *status, bool isProject); +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); + +static void __glue_fillPatchGlobals__(const string &name); +static void __glue_fillPatchChannels__(bool isProject); +static void __glue_fillPatchColumns__(); + +#ifdef WITH_VST +static void __glue_fillPatchGlobalsPlugins__(gVector *host, gVector *patch); +#endif + +static void __setProgressBar__(class gProgress *status, float v); + +#endif diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp index e790253..2194bd3 100644 --- a/src/gui/dialogs/gd_about.cpp +++ b/src/gui/dialogs/gd_about.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_about * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,9 +24,10 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ +#include #include "../../core/conf.h" #include "../../core/const.h" #include "../../core/kernelAudio.h" @@ -42,9 +43,11 @@ extern Conf G_Conf; gdAbout::gdAbout() #ifdef WITH_VST -: gWindow(340, 405, "About Giada") { +: gWindow(340, 405, "About Giada") +{ #else -: gWindow(340, 320, "About Giada") { +: gWindow(340, 320, "About Giada") +{ #endif if (G_Conf.aboutX) @@ -67,17 +70,19 @@ gdAbout::gdAbout() char message[512]; sprintf( message, - "Version " VERSIONE " (" __DATE__ ")\n\n" + "Version " G_VERSION_STR " (" __DATE__ ")\n\n" "Developed by Monocasual\n" "Based on FLTK (%d.%d.%d), RtAudio (%s),\n" - "RtMidi (%s), libsamplerate and libsndfile\n\n" + "RtMidi (%s), libsamplerate, Jansson (%s) \n" + "and libsndfile\n\n" "Released under the terms of the GNU General\n" "Public License (GPL v3)\n\n" "News, infos, contacts and documentation:\n" "www.giadamusic.com", - FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, + FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, kernelAudio::getRtAudioVersion().c_str(), - kernelMidi::getRtMidiVersion().c_str()); + kernelMidi::getRtMidiVersion().c_str(), + JANSSON_VERSION); int tw = 0; int th = 0; @@ -103,24 +108,26 @@ gdAbout::gdAbout() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -gdAbout::~gdAbout() { +gdAbout::~gdAbout() +{ G_Conf.aboutX = x(); G_Conf.aboutY = y(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdAbout::cb_close(Fl_Widget *w, void *p) { ((gdAbout*)p)->__cb_close(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gdAbout::__cb_close() { +void gdAbout::__cb_close() +{ do_callback(); } diff --git a/src/gui/dialogs/gd_beatsInput.cpp b/src/gui/dialogs/gd_beatsInput.cpp index bf7455f..fb3aeba 100644 --- a/src/gui/dialogs/gd_beatsInput.cpp +++ b/src/gui/dialogs/gd_beatsInput.cpp @@ -28,7 +28,6 @@ #include "../../utils/gui_utils.h" -#include "../../core/patch.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../glue/glue.h" diff --git a/src/gui/dialogs/gd_browser.cpp b/src/gui/dialogs/gd_browser.cpp index d415ae0..c3eec4a 100644 --- a/src/gui/dialogs/gd_browser.cpp +++ b/src/gui/dialogs/gd_browser.cpp @@ -15,7 +15,7 @@ * 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 + * Giada - Your Hardcore Loopmacghine 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. @@ -33,9 +33,11 @@ #include "../../core/pluginHost.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/storage.h" #include "../elems/ge_browser.h" #include "../elems/ge_channel.h" #include "../elems/ge_keyboard.h" @@ -45,6 +47,10 @@ #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; @@ -106,7 +112,7 @@ gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int t else if (type == BROWSER_SAVE_PATCH) { ok->callback(cb_save_patch, (void*)this); - name->value(G_Patch.name[0] == '\0' ? "my_patch.gptc" : G_Patch.name); + name->value(G_Patch.name == "" ? "my_patch.gptc" : G_Patch.name.c_str()); name->maximum_size(MAX_PATCHNAME_LEN+5); // +5 for ".gptc" } else @@ -177,27 +183,8 @@ void gdBrowser::__cb_load_patch() { if (browser->text(browser->value()) == NULL) return; - /* patchFile is the file to open. - * For patches: browser->get_selected_item() - * for projects: browser->get_selected_item() without extention + - * patch name appended */ - - std::string patchFile = browser->get_selected_item();; - bool isProject; - - if (gIsProject(browser->get_selected_item())) { - std::string patchName = gGetProjectName(browser->get_selected_item()); -#if defined(__linux__) || defined(__APPLE__) - patchFile = patchFile+"/"+patchName+".gptc"; -#elif defined(_WIN32) - patchFile = patchFile+"\\"+patchName+".gptc"; -#endif - isProject = true; - } - else - isProject = false; - - int res = glue_loadPatch(patchFile.c_str(), browser->path_obj->value(), status, isProject); + bool isProject = gIsProject(browser->get_selected_item()); + int res = glue_loadPatch(browser->get_selected_item(), status, isProject); if (res == PATCH_UNREADABLE) { status->hide(); @@ -206,7 +193,8 @@ void gdBrowser::__cb_load_patch() { else gdAlert("This patch is unreadable."); } - else if (res == PATCH_INVALID) { + else + if (res == PATCH_INVALID) { status->hide(); if (isProject) gdAlert("This project is not valid."); @@ -230,7 +218,7 @@ void gdBrowser::__cb_save_sample() { /* bruteforce check extension. */ - std::string filename = gStripExt(name->value()); + string filename = gStripExt(name->value()); char fullpath[PATH_MAX]; sprintf(fullpath, "%s/%s.wav", where->value(), filename.c_str()); @@ -276,7 +264,7 @@ void gdBrowser::__cb_down() { if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) { if (gIsProject(path)) { - std::string tmp = browser->text(browser->value()); + string tmp = browser->text(browser->value()); tmp.erase(0, 4); name->value(tmp.c_str()); } @@ -304,26 +292,20 @@ void gdBrowser::__cb_up() { /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_save_patch() { - +void gdBrowser::__cb_save_patch() +{ if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a file name."); return; } - /* if name->value() contains ".gptc" */ - - char ext[6] = ".gptc"; - if (strstr(name->value(), ".gptc") != NULL) - ext[0] = '\0'; + string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gptc"; - char fullpath[PATH_MAX]; - sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext); - if (gFileExists(fullpath)) + if (gFileExists(fullpath.c_str())) if (!gdConfirmWin("Warning", "File exists: overwrite?")) return; - if (glue_savePatch(fullpath, name->value(), false)) // false == not a project + if (glue_savePatch(fullpath, name->value(), false)) // false == not a project do_callback(); else gdAlert("Unable to save the patch!"); @@ -333,27 +315,16 @@ void gdBrowser::__cb_save_patch() { /* -------------------------------------------------------------------------- */ -void gdBrowser::__cb_save_project() { - +void gdBrowser::__cb_save_project() +{ if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a project name."); return; } - /* check if name->value() contains ".gprj" */ - - char ext[6] = ".gprj"; - if (strstr(name->value(), ".gprj") != NULL) - ext[0] = '\0'; - - char fullpath[PATH_MAX]; -#if defined(_WIN32) - sprintf(fullpath, "%s\\%s%s", where->value(), name->value(), ext); -#else - sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext); -#endif + string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gprj"; - if (gIsProject(fullpath) && !gdConfirmWin("Warning", "Project exists: overwrite?")) + if (gIsProject(fullpath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?")) return; if (glue_saveProject(fullpath, name->value())) @@ -372,14 +343,14 @@ void gdBrowser::__cb_loadPlugin() { if (browser->text(browser->value()) == NULL) return; - int res = G_PluginHost.addPlugin(browser->get_selected_item(), stackType, ch); + Plugin *p = G_PluginHost.addPlugin(browser->get_selected_item(), stackType, ch); /* store the folder path inside G_Conf, in order to reuse it the * next time. */ G_Conf.setPath(G_Conf.pluginPath, where->value()); - if (res) + if (p != NULL) do_callback(); else gdAlert("Unable to load the selected plugin!"); diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp index 45f8b15..7e9c213 100644 --- a/src/gui/dialogs/gd_config.cpp +++ b/src/gui/dialogs/gd_config.cpp @@ -29,7 +29,7 @@ #include "../../core/conf.h" #include "../../core/midiMapConf.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../utils/gui_utils.h" @@ -41,9 +41,9 @@ #include "gd_browser.h" -extern Patch G_Patch; -extern Conf G_Conf; -extern bool G_audio_status; +extern Patch_DEPR_ G_Patch_DEPR_; +extern Conf G_Conf; +extern bool G_audio_status; extern MidiMapConf G_MidiMap; diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp index 0289763..1fc0c67 100644 --- a/src/gui/dialogs/gd_mainWindow.cpp +++ b/src/gui/dialogs/gd_mainWindow.cpp @@ -40,7 +40,7 @@ #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/init.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/conf.h" #include "../../glue/glue.h" #include "../elems/ge_keyboard.h" @@ -60,7 +60,7 @@ extern Mixer G_Mixer; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; extern gdMainWindow *mainWin; extern bool G_quit; diff --git a/src/gui/elems/ge_channel.cpp b/src/gui/elems/ge_channel.cpp index 945ece4..a9a37d5 100644 --- a/src/gui/elems/ge_channel.cpp +++ b/src/gui/elems/ge_channel.cpp @@ -30,7 +30,7 @@ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" @@ -57,7 +57,7 @@ extern Mixer G_Mixer; extern Conf G_Conf; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; diff --git a/src/gui/elems/ge_channelButton.cpp b/src/gui/elems/ge_channelButton.cpp index 4eef502..1480b54 100644 --- a/src/gui/elems/ge_channelButton.cpp +++ b/src/gui/elems/ge_channelButton.cpp @@ -28,9 +28,13 @@ #include "../../core/const.h" +#include "../../utils/utils.h" #include "ge_channelButton.h" +using std::string; + + gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l) : gClick(x, y, w, h, l), key("") {} @@ -38,7 +42,7 @@ gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l) /* -------------------------------------------------------------------------- */ -void gChannelButton::setKey(const char *k) +void gChannelButton::setKey(const string &k) { key = k; } @@ -47,6 +51,21 @@ void gChannelButton::setKey(const char *k) /* -------------------------------------------------------------------------- */ +void gChannelButton::setKey(int k) +{ + if (k == 0) + key = ""; + else { + // FIXME - this crap won't work with unicode/utf-8 + char c = (char) k; + key = c; + } +} + + +/* -------------------------------------------------------------------------- */ + + void gChannelButton::draw() { gClick::draw(); diff --git a/src/gui/elems/ge_channelButton.h b/src/gui/elems/ge_channelButton.h index a3bb22b..86f6736 100644 --- a/src/gui/elems/ge_channelButton.h +++ b/src/gui/elems/ge_channelButton.h @@ -34,11 +34,14 @@ #include "ge_mixed.h" +using std::string; + + class gChannelButton : public gClick { private: - std::string key; + string key; public: @@ -47,7 +50,8 @@ public: virtual int handle(int e) = 0; void draw(); - void setKey(const char *k); + void setKey(const string &k); + void setKey(int k); void setPlayMode(); void setEndingMode(); void setDefaultMode(const char *l=0); diff --git a/src/gui/elems/ge_column.cpp b/src/gui/elems/ge_column.cpp index 12c479c..de10451 100644 --- a/src/gui/elems/ge_column.cpp +++ b/src/gui/elems/ge_column.cpp @@ -29,7 +29,7 @@ #include "../../core/mixer.h" #include "../../core/conf.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" @@ -50,7 +50,7 @@ extern Mixer G_Mixer; extern Conf G_Conf; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; @@ -71,7 +71,7 @@ gColumn::gColumn(int X, int Y, int W, int H, int index, gKeyboard *parent) end(); resizer = new gResizerBar(x()+w(), y(), 16, h(), false); - resizer->setMinSize(140); + resizer->setMinSize(MIN_COLUMN_WIDTH); parent->add(resizer); addChannelBtn->callback(cb_addChannel, (void*)this); @@ -93,6 +93,7 @@ gColumn::~gColumn() /* -------------------------------------------------------------------------- */ + int gColumn::handle(int e) { switch (e) { @@ -194,28 +195,12 @@ void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChan gChannel *gColumn::addChannel(class Channel *ch) { + int currentY = y() + children() * 24; gChannel *gch = NULL; - if (ch->type == CHANNEL_SAMPLE) - gch = (gSampleChannel*) new gSampleChannel( - x(), - y() + children() * 24, - 600, // (1) see notes below - 20, - (SampleChannel*) ch); + gch = (gSampleChannel*) new gSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); else - gch = (gMidiChannel*) new gMidiChannel( - x(), - y() + children() * 24, - w(), - 20, - (MidiChannel*) ch); - - /* (1) we create a new sample channel with a fake width, instead of w() (i.e. - the column width), in case the column is too narrow to display all widgets. - This workaround prevents the widgets to disappear if they have an initial - negative width. MidiChannel does not need such hack because it already fits - nicely in a collapsed column. */ + gch = (gMidiChannel*) new gMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); add(gch); resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop @@ -302,3 +287,16 @@ void gColumn::clear(bool full) } } } + + +/* -------------------------------------------------------------------------- */ + + +Channel *gColumn::getChannel(int i) +{ + gChannel *gch = (gChannel*) child(i); + if (gch->type == CHANNEL_SAMPLE) + return ((gSampleChannel*) child(i))->ch; + else + return ((gMidiChannel*) child(i))->ch; +} diff --git a/src/gui/elems/ge_column.h b/src/gui/elems/ge_column.h index 84ebc8a..f0e0c9c 100644 --- a/src/gui/elems/ge_column.h +++ b/src/gui/elems/ge_column.h @@ -80,6 +80,10 @@ public: void refreshChannels(); + /* getChannel */ + + Channel *getChannel(int i); + /* clear * remove all channels from the column. If full==true, delete also the * "add new channel" button. This method ovverrides the inherited one @@ -92,6 +96,7 @@ public: inline int getIndex() { return index; } inline void setIndex(int i) { index = i; } inline bool isEmpty() { return children() == 1; } + inline int countChannels() { return children(); } }; diff --git a/src/gui/elems/ge_keyboard.cpp b/src/gui/elems/ge_keyboard.cpp index 24d47bd..bf0e1bd 100644 --- a/src/gui/elems/ge_keyboard.cpp +++ b/src/gui/elems/ge_keyboard.cpp @@ -30,7 +30,7 @@ #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/const.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../glue/glue.h" @@ -46,7 +46,7 @@ extern Mixer G_Mixer; extern Conf G_Conf; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; @@ -160,6 +160,10 @@ void gKeyboard::organizeColumns() addColumnBtn->position(columns.last()->x() + columns.last()->w() + 16, y()); + /* recompute col indexes */ + + refreshColIndexes(); + redraw(); } @@ -167,7 +171,10 @@ void gKeyboard::organizeColumns() /* -------------------------------------------------------------------------- */ -void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) { ((gKeyboard*)p)->__cb_addColumn(); } +void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) +{ + ((gKeyboard*)p)->__cb_addColumn(DEFAULT_COLUMN_WIDTH); +} /* -------------------------------------------------------------------------- */ @@ -175,7 +182,7 @@ void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) { ((gKeyboard*)p)->__cb_addC gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) { - gColumn *col = getColumn(colIndex); + gColumn *col = getColumnByIndex(colIndex); /* no column with index 'colIndex' found? Just create it and set its index to 'colIndex'. */ @@ -205,7 +212,7 @@ void gKeyboard::refreshColumns() /* -------------------------------------------------------------------------- */ -gColumn *gKeyboard::getColumn(int index) +gColumn *gKeyboard::getColumnByIndex(int index) { for (unsigned i=0; igetIndex() == index) @@ -331,36 +338,60 @@ void gKeyboard::printChannelMessage(int res) gdAlert("Unknown error."); } + /* -------------------------------------------------------------------------- */ -void gKeyboard::__cb_addColumn() +void gKeyboard::__cb_addColumn(int width) { int colx; int colxw; - int colw = 380; + int gap = 16; if (columns.size == 0) { colx = x() - xposition(); // mind the offset with xposition() - colxw = colx + colw; + colxw = colx + width; } else { gColumn *prev = columns.last(); - colx = prev->x()+prev->w() + 16; - colxw = colx + colw; + colx = prev->x()+prev->w() + gap; + colxw = colx + width; } /* add gColumn to gKeyboard and to columns vector */ - gColumn *gc = new gColumn(colx, y(), colw-20, 2000, indexColumn, this); + gColumn *gc = new gColumn(colx, y(), width, 2000, indexColumn, this); add(gc); columns.add(gc); indexColumn++; /* move addColumn button */ - addColumnBtn->position(colxw-4, y()); + addColumnBtn->position(colxw + gap, y()); redraw(); - gLog("[gKeyboard::__cb_addColumn] new column added (index = %d), total count=%d, addColumn(x)=%d\n", - gc->getIndex(), columns.size, addColumnBtn->x()); + gLog("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", + gc->getIndex(), width, columns.size, addColumnBtn->x()); + + /* recompute col indexes */ + + refreshColIndexes(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gKeyboard::addColumn(int width) +{ + __cb_addColumn(width); +} + + +/* -------------------------------------------------------------------------- */ + + +void gKeyboard::refreshColIndexes() +{ + for (unsigned i=0; isetIndex(i); } diff --git a/src/gui/elems/ge_keyboard.h b/src/gui/elems/ge_keyboard.h index be79c39..47575b1 100644 --- a/src/gui/elems/ge_keyboard.h +++ b/src/gui/elems/ge_keyboard.h @@ -37,6 +37,7 @@ #include #include #include "../elems/ge_column.h" +#include "../../core/const.h" #include "../../utils/utils.h" @@ -44,8 +45,14 @@ class gKeyboard : public Fl_Scroll { private: + /* refreshColIndexes + * Recompute all column indexes in order to avoid any gaps between them. + * Indexes must always be contiguous! */ + + void refreshColIndexes(); + static void cb_addColumn (Fl_Widget *v, void *p); - inline void __cb_addColumn(); + inline void __cb_addColumn(int width=DEFAULT_COLUMN_WIDTH); bool bckspcPressed; bool endPressed; @@ -78,10 +85,16 @@ public: /* addChannel * add a new channel to gChannels. Used by callbacks and during * patch loading. Requires Channel (and not gChannel). If build is - * set to true, also generate the corresponding column.*/ + * set to true, also generate the corresponding column if column (index) does + * not exist yet. */ gChannel *addChannel(int column, class Channel *ch, bool build=false); + /* addColumn + * add a new column to the top of the stack. */ + + void addColumn(int width=380); + /* deleteChannel * delete a channel from gChannels<> where gChannel->ch == ch and remove * it from the stack. */ @@ -109,10 +122,15 @@ public: void refreshColumns(); - /* getColumn + /* getColumnByIndex * return the column with index 'index', or NULL if not found. */ - gColumn *getColumn(int index); + gColumn *getColumnByIndex(int index); + + /* getColumn + * return the column with from columns->at(i). */ + + inline gColumn *getColumn(int i) { return columns.at(i); } /* clear * delete all channels and groups. */ @@ -138,7 +156,7 @@ public: * return the width in pixel of i-th column. Warning: 'i' is the i-th column * in the column array, NOT the index. */ - inline int getColumnWidth(int i) { return getColumn(i)->w(); } + inline int getColumnWidth(int i) { return getColumnByIndex(i)->w(); } }; diff --git a/src/gui/elems/ge_midiChannel.cpp b/src/gui/elems/ge_midiChannel.cpp index 68ba4e7..7a372ba 100644 --- a/src/gui/elems/ge_midiChannel.cpp +++ b/src/gui/elems/ge_midiChannel.cpp @@ -30,7 +30,7 @@ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" @@ -59,7 +59,7 @@ extern Mixer G_Mixer; extern Conf G_Conf; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; @@ -105,6 +105,7 @@ gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch) solo->callback(cb_solo, (void*)this); mainButton->callback(cb_openMenu, (void*)this); + vol->callback(cb_changeVol, (void*)this); ch->guiChannel = this; @@ -278,6 +279,8 @@ void gMidiChannel::update() mute->value(ch->mute); solo->value(ch->solo); + mainButton->setKey(ch->key); + #ifdef WITH_VST fx->full = ch->plugins.size > 0; #endif diff --git a/src/gui/elems/ge_sampleChannel.cpp b/src/gui/elems/ge_sampleChannel.cpp index ff678d9..a68f3df 100644 --- a/src/gui/elems/ge_sampleChannel.cpp +++ b/src/gui/elems/ge_sampleChannel.cpp @@ -30,7 +30,7 @@ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" -#include "../../core/patch.h" +#include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" @@ -58,7 +58,7 @@ extern Mixer G_Mixer; extern Conf G_Conf; -extern Patch G_Patch; +extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; @@ -108,6 +108,7 @@ gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel * solo->callback(cb_solo, (void*)this); mainButton->callback(cb_openMenu, (void*)this); + vol->callback(cb_changeVol, (void*)this); ch->guiChannel = this; @@ -452,8 +453,11 @@ void gSampleChannel::update() mute->value(ch->mute); solo->value(ch->solo); + mainButton->setKey(ch->key); + #ifdef WITH_VST fx->full = ch->plugins.size > 0; + fx->redraw(); #endif } @@ -532,6 +536,13 @@ void gSampleChannel::resize(int X, int Y, int W, int H) mainButton->size(w() - BREAK_DELTA, mainButton->h()); mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); solo->resize(mute->x()+mute->w()+4, y(), 20, 20); + + /* The followings are useless on manual resizing, but useful when a channel + * is added from a patch with a small width. */ + + modeBox->hide(); + if (readActions) + readActions->hide(); } else if (w() < BREAK_MODE_BOX) { @@ -548,9 +559,8 @@ void gSampleChannel::resize(int X, int Y, int W, int H) modeBox->show(); mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h()); modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - if (readActions) { + if (readActions) readActions->hide(); - } } else { if (readActions) { diff --git a/src/gui/elems/ge_sampleChannel.h b/src/gui/elems/ge_sampleChannel.h index 0aad470..9ba701a 100644 --- a/src/gui/elems/ge_sampleChannel.h +++ b/src/gui/elems/ge_sampleChannel.h @@ -82,7 +82,7 @@ public: void addActionButton(); void delActionButton(bool force=false); - + class gModeBox *modeBox; class gClick *readActions; diff --git a/src/main.cpp b/src/main.cpp index a70c616..d7829df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,8 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -22,7 +22,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -31,6 +31,7 @@ #endif #include "core/init.h" #include "core/const.h" +#include "core/patch_DEPR_.h" #include "core/patch.h" #include "core/conf.h" #include "core/midiMapConf.h" @@ -52,9 +53,10 @@ Mixer G_Mixer; bool G_quit; bool G_audio_status; bool G_midiStatus; -Patch G_Patch; -Conf G_Conf; -MidiMapConf G_MidiMap; +Patch_DEPR_ G_Patch_DEPR_; +Patch G_Patch; +Conf G_Conf; +MidiMapConf G_MidiMap; gdMainWindow *mainWin; #ifdef WITH_VST diff --git a/src/utils/gui_utils.cpp b/src/utils/gui_utils.cpp index 7625576..872aee5 100644 --- a/src/utils/gui_utils.cpp +++ b/src/utils/gui_utils.cpp @@ -28,7 +28,7 @@ #include "../core/mixer.h" -#include "../core/patch.h" +#include "../core/patch_DEPR_.h" #include "../core/recorder.h" #include "../core/wave.h" #include "../core/pluginHost.h" @@ -48,7 +48,7 @@ extern Mixer G_Mixer; extern unsigned G_beats; extern bool G_audio_status; -extern Patch G_patch; +extern Patch_DEPR_ G_patch; extern Conf G_conf; extern uint32_t G_time; extern gdMainWindow *mainWin; @@ -98,8 +98,9 @@ int gu_getBlinker() void gu_updateControls() { - for (unsigned i=0; iguiChannel->update(); + } mainWin->inOut->setOutVol(G_Mixer.outVol); mainWin->inOut->setInVol(G_Mixer.inVol); @@ -124,7 +125,7 @@ void gu_updateControls() void gu_update_win_label(const char *c) { - std::string out = VERSIONE_STR; + std::string out = G_APP_NAME; out += " - "; out += c; mainWin->copy_label(out.c_str()); diff --git a/src/utils/gvector.h b/src/utils/gvector.h new file mode 100644 index 0000000..e36ef90 --- /dev/null +++ b/src/utils/gvector.h @@ -0,0 +1,146 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gvector + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 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 GVECTOR_H +#define GVECTOR_H + + +#include "log.h" + + +/* gVector + * lightweight template class. */ + +template class gVector +{ +public: + + /* gVector() + * default constructor, no parameters */ + + gVector() : size(0), s(NULL) {} + + /* gVector(const &) + * copy-constructor, when gVector a = b (where b is another gVector). + * Default constructor doesn't copy referenced objects, so we need + * to re-allocate the internal stack for the copied object */ + + gVector(const gVector &other) + { + s = new T[other.size]; + for (unsigned i=0; i size-1) gLog("[vector] del() outside! requested=%d, size=%d\n", p, size); + T *tmp = new T[size-1]; + unsigned i=0; + unsigned j=0; + while (i 0) { + delete [] s; + s = NULL; + size = 0; + } + } + + + void swap(unsigned x, unsigned y) + { + T tmp = s[x]; + s[x] = s[y]; + s[y] = tmp; + } + + + T &at(unsigned p) + { + if (p > size-1) gLog("[vector] at() outside! requested=%d, size=%d\n", p, size); + return s[p]; + } + + + T &last() + { + return s[size-1]; + } + + + unsigned size; + T *s; // stack (array of T) +}; + + +#endif diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index c0b8c1a..a45199d 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -50,6 +50,8 @@ #endif +using std::string; + bool gFileExists(const char *filename) { FILE *fh = fopen(filename, "rb"); @@ -90,7 +92,7 @@ bool gIsDir(const char *path) * FIXME - consider native functions CFBundle... */ if (ret) { - std::string tmp = path; + string tmp = path; tmp += "/Contents/Info.plist"; if (gFileExists(tmp.c_str())) ret = false; @@ -137,17 +139,17 @@ bool gMkdir(const char *path) /* -------------------------------------------------------------------------- */ - -std::string gBasename(const char *path) +/* TODO - avoid this shit, just wrap the other call */ +string gBasename(const char *path) { - std::string out = path; + string out = path; out.erase(0, out.find_last_of(gGetSlash().c_str())+1); return out; } -std::string gBasename(const std::string &s) +string gBasename(const string &s) { - std::string out = s; + string out = s; out.erase(0, out.find_last_of(gGetSlash().c_str())+1); return out; } @@ -156,9 +158,9 @@ std::string gBasename(const std::string &s) /* -------------------------------------------------------------------------- */ -std::string gDirname(const char *path) +string gDirname(const char *path) { - std::string out = path; + string out = path; out.erase(out.find_last_of(gGetSlash().c_str())); return out; } @@ -167,7 +169,7 @@ std::string gDirname(const char *path) /* -------------------------------------------------------------------------- */ -std::string gGetCurrentPath() +string gGetCurrentPath() { char buf[PATH_MAX]; #if defined(__WIN32) @@ -184,7 +186,7 @@ std::string gGetCurrentPath() /* -------------------------------------------------------------------------- */ -std::string gGetExt(const char *file) +string gGetExt(const char *file) { int len = strlen(file); int pos = len; @@ -195,7 +197,7 @@ std::string gGetExt(const char *file) } if (pos==0) return ""; - std::string out = file; + string out = file; return out.substr(pos+1, len); } @@ -203,7 +205,7 @@ std::string gGetExt(const char *file) /* -------------------------------------------------------------------------- */ -std::string gStripExt(const char *file) +string gStripExt(const char *file) { int len = strlen(file); int pos = -1; @@ -212,11 +214,17 @@ std::string gStripExt(const char *file) pos = i; break; } - std::string out = file; + string out = file; return pos == -1 ? out : out.substr(0, pos); } +string gStripExt(const string &s) +{ + return s.substr(0, s.find_last_of(".")); +} + + /* -------------------------------------------------------------------------- */ @@ -244,9 +252,9 @@ bool gIsPatch(const char *path) /* -------------------------------------------------------------------------- */ -std::string gGetProjectName(const char *path) +string gGetProjectName(const char *path) { - std::string out; + string out; out = gStripExt(path); int i = out.size(); @@ -268,7 +276,7 @@ std::string gGetProjectName(const char *path) /* -------------------------------------------------------------------------- */ -std::string gGetSlash() // TODO - create SLASH macro or constant +string gGetSlash() { #if defined(_WIN32) return "\\"; @@ -281,7 +289,7 @@ std::string gGetSlash() // TODO - create SLASH macro or constant /* -------------------------------------------------------------------------- */ -std::string gItoa(int i) +string gItoa(int i) { std::stringstream out; out << i; @@ -292,14 +300,14 @@ std::string gItoa(int i) /* -------------------------------------------------------------------------- */ -std::string gTrim(const char *f) +string gTrim(const char *f) { - std::string out = f; + string out = f; return gTrim(out); } -std::string gTrim(const std::string &s) +string gTrim(const string &s) { std::size_t first = s.find_first_not_of(" \n\t"); std::size_t last = s.find_last_not_of(" \n\t"); @@ -310,10 +318,10 @@ std::string gTrim(const std::string &s) /* -------------------------------------------------------------------------- */ -std::string gReplace(std::string in, const std::string& search, const std::string& replace) +string gReplace(string in, const string& search, const string& replace) { size_t pos = 0; - while ((pos = in.find(search, pos)) != std::string::npos) { + while ((pos = in.find(search, pos)) != string::npos) { in.replace(pos, search.length(), replace); pos += replace.length(); } @@ -324,9 +332,9 @@ std::string gReplace(std::string in, const std::string& search, const std::strin /* -------------------------------------------------------------------------- */ -std::string gStripFileUrl(const char *f) +string gStripFileUrl(const char *f) { - std::string out = f; + string out = f; out = gReplace(out, "file://", ""); out = gReplace(out, "%20", " "); return out; @@ -336,7 +344,7 @@ std::string gStripFileUrl(const char *f) /* -------------------------------------------------------------------------- */ -std::string gGetHomePath() +string gGetHomePath() { char path[PATH_MAX]; @@ -362,17 +370,17 @@ std::string gGetHomePath() #endif - return std::string(path); + return string(path); } /* -------------------------------------------------------------------------- */ -void gSplit(std::string in, std::string sep, gVector *v) +void gSplit(string in, string sep, gVector *v) { - std::string full = in; - std::string token = ""; + string full = in; + string token = ""; size_t curr = 0; size_t next = -1; do { @@ -382,5 +390,5 @@ void gSplit(std::string in, std::string sep, gVector *v) if (token != "") v->add(token); } - while (next != std::string::npos); + while (next != string::npos); } diff --git a/src/utils/utils.h b/src/utils/utils.h index 8f832ad..6316577 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -34,118 +34,10 @@ #include #include #include "log.h" +#include "gvector.h" -/* gVector - * lightweight template class. */ - -template class gVector -{ -public: - - /* gVector() - * default constructor, no parameters */ - - gVector() : size(0), s(NULL) {} - - /* gVector(const &) - * copy-constructor, when gVector a = b (where b is gVector). - * Default constructor doesn't copy referenced ojbects, so we need - * to re-allocate the internal stack for the copied object */ - - gVector(const gVector &other) - { - s = new T[other.size]; - for (unsigned i=0; i size-1) gLog("[vector] del() outside! requested=%d, size=%d\n", p, size); - T *tmp = new T[size-1]; - unsigned i=0; - unsigned j=0; - while (i 0) { - delete [] s; - s = NULL; - size = 0; - } - } - - - void swap(unsigned x, unsigned y) - { - T tmp = s[x]; - s[x] = s[y]; - s[y] = tmp; - } - - - T &at(unsigned p) - { - if (p > size-1) gLog("[vector] at() outside! requested=%d, size=%d\n", p, size); - return s[p]; - } - - - T &last() - { - return s[size-1]; - } - - - unsigned size; - T *s; // stack (array of T) -}; - - -/* ------------------------------------------------------------------ */ +using std::string; bool gFileExists(const char *path); @@ -160,32 +52,33 @@ bool gIsPatch(const char *path); bool gMkdir(const char *path); -std::string gBasename(const char *path); -std::string gBasename(const std::string &s); +string gBasename(const char *path); +string gBasename(const string &s); -std::string gReplace(std::string in, const std::string& search, const std::string& replace); +string gReplace(string in, const string& search, const string& replace); -std::string gDirname(const char *path); +string gDirname(const char *path); -std::string gTrim(const char *path); -std::string gTrim(const std::string &s); +string gTrim(const char *path); +string gTrim(const string &s); -std::string gGetCurrentPath(); +string gGetCurrentPath(); -std::string gGetHomePath(); +string gGetHomePath(); -std::string gStripFileUrl(const char *path); +string gStripFileUrl(const char *path); -std::string gGetExt(const char *path); +string gGetExt(const char *path); -std::string gStripExt(const char *path); +string gStripExt(const char *path); +string gStripExt(const string &s); -std::string gGetProjectName(const char *path); +string gGetProjectName(const char *path); // TODO - useless! -std::string gGetSlash(); +string gGetSlash(); -std::string gItoa(int i); +string gItoa(int i); -void gSplit(std::string in, std::string sep, gVector *v); +void gSplit(string in, string sep, gVector *v); #endif diff --git a/tests/patch.cpp b/tests/patch.cpp new file mode 100644 index 0000000..a36decf --- /dev/null +++ b/tests/patch.cpp @@ -0,0 +1,229 @@ +#include "../src/core/patch.h" +#include "../src/core/const.h" +#include "catch.hpp" + + +using std::string; + + +TEST_CASE("Test Patch class") +{ + Patch patch; + string filename = "./test-patch.json"; + + SECTION("test write") + { + Patch::action_t action1; + Patch::action_t action2; + Patch::channel_t channel1; + Patch::channel_t channel2; + Patch::column_t column; +#ifdef WITH_VST + Patch::plugin_t plugin1; + Patch::plugin_t plugin2; + Patch::plugin_t plugin3; +#endif + + action1.type = 0; + action1.frame = 50000; + action1.fValue = 0.3f; + action1.iValue = 1000; + action2.type = 2; + action2.frame = 589; + action2.fValue = 1.0f; + action2.iValue = 130; + channel1.actions.add(action1); + channel1.actions.add(action2); + +#ifdef WITH_VST + plugin1.path = "/path/to/plugin1"; + plugin1.bypass = false; + plugin1.params.add(0.0f); + plugin1.params.add(0.1f); + plugin1.params.add(0.2f); + channel1.plugins.add(plugin1); + + plugin2.path = "/another/path/to/plugin2"; + plugin2.bypass = true; + plugin2.params.add(0.6f); + plugin2.params.add(0.6f); + plugin2.params.add(0.6f); + plugin2.params.add(0.0f); + plugin2.params.add(1.0f); + plugin2.params.add(1.0f); + plugin2.params.add(0.333f); + channel1.plugins.add(plugin2); +#endif + + channel1.type = CHANNEL_SAMPLE; + channel1.index = 666; + channel1.column = 0; + channel1.mute = 0; + channel1.mute_s = 0; + channel1.solo = 0; + channel1.volume = 1.0f; + channel1.panLeft = 0.5f; + channel1.panRight = 0.5f; + channel1.midiIn = true; + channel1.midiInKeyPress = UINT32_MAX; // check maximum value + channel1.midiInKeyRel = 1; + channel1.midiInKill = 2; + channel1.midiInVolume = 3; + channel1.midiInMute = 4; + channel1.midiInSolo = 5; + channel1.midiOutL = true; + channel1.midiOutLplaying = 7; + channel1.midiOutLmute = 8; + channel1.midiOutLsolo = 9; + channel1.samplePath = "/tmp/test.wav"; + channel1.key = 666; + channel1.mode = 0; + channel1.begin = 0; + channel1.end = 0; + channel1.boost = 0; + channel1.recActive = 0; + channel1.pitch = 1.2f; + channel1.midiInReadActions = 0; + channel1.midiInPitch = 0; + channel1.midiOut = 0; + channel1.midiOutChan = 5; + patch.channels.add(channel1); + + column.index = 0; + column.width = 500; + patch.columns.add(column); + + patch.header = "GPTCH"; + patch.version = "1.0"; + patch.versionMajor = 6; + patch.versionMinor = 6; + patch.versionPatch = 6; + patch.name = "test patch"; + patch.bpm = 100.0f; + patch.bars = 4; + patch.beats = 23; + patch.quantize = 1; + patch.masterVolIn = 1.0f; + patch.masterVolOut = 0.7f; + patch.metronome = 0; + patch.lastTakeId = 0; + patch.samplerate = 44100; + +#ifdef WITH_VST + + patch.masterInPlugins.add(plugin1); + patch.masterOutPlugins.add(plugin2); + +#endif + + REQUIRE(patch.write(filename) == 1); + } + + SECTION("test read") + { + REQUIRE(patch.read(filename) == PATCH_READ_OK); + REQUIRE(patch.header == "GPTCH"); + REQUIRE(patch.version == "1.0"); + REQUIRE(patch.versionMajor == 6); + REQUIRE(patch.versionMinor == 6); + REQUIRE(patch.versionPatch == 6); + REQUIRE(patch.name == "test patch"); + REQUIRE(patch.bpm == Approx(100.0f)); + REQUIRE(patch.bars == 4); + REQUIRE(patch.beats == 23); + REQUIRE(patch.quantize == 1); + REQUIRE(patch.masterVolIn == Approx(1.0f)); + REQUIRE(patch.masterVolOut == Approx(0.7f)); + REQUIRE(patch.metronome == 0); + REQUIRE(patch.lastTakeId == 0); + REQUIRE(patch.samplerate == 44100); + + Patch::column_t column0 = patch.columns.at(0); + REQUIRE(column0.index == 0); + REQUIRE(column0.width == 500); + + Patch::channel_t channel0 = patch.channels.at(0); + REQUIRE(channel0.type == CHANNEL_SAMPLE); + REQUIRE(channel0.index == 666); + REQUIRE(channel0.column == 0); + REQUIRE(channel0.mute == 0); + REQUIRE(channel0.mute_s == 0); + REQUIRE(channel0.solo == 0); + REQUIRE(channel0.volume == Approx(1.0f)); + REQUIRE(channel0.panLeft == Approx(0.5f)); + REQUIRE(channel0.panRight == Approx(0.5f)); + REQUIRE(channel0.midiIn == true); + REQUIRE(channel0.midiInKeyPress == UINT32_MAX); + REQUIRE(channel0.midiInKeyRel == 1); + REQUIRE(channel0.midiInKill == 2); + REQUIRE(channel0.midiInVolume == 3); + REQUIRE(channel0.midiInMute == 4); + REQUIRE(channel0.midiInSolo == 5); + REQUIRE(channel0.midiOutL == true); + REQUIRE(channel0.midiOutLplaying == 7); + REQUIRE(channel0.midiOutLmute == 8); + REQUIRE(channel0.midiOutLsolo == 9); + REQUIRE(channel0.samplePath == "/tmp/test.wav"); + REQUIRE(channel0.key == 666); + REQUIRE(channel0.mode == 0); + REQUIRE(channel0.begin == 0); + REQUIRE(channel0.end == 0); + REQUIRE(channel0.boost == 0); + REQUIRE(channel0.recActive == 0); + REQUIRE(channel0.pitch == Approx(1.2f)); + REQUIRE(channel0.midiInReadActions == 0); + REQUIRE(channel0.midiInPitch == 0); + REQUIRE(channel0.midiOut == 0); + REQUIRE(channel0.midiOutChan == 5); + + Patch::action_t action0 = channel0.actions.at(0); + REQUIRE(action0.type == 0); + REQUIRE(action0.frame == 50000); + REQUIRE(action0.fValue == Approx(0.3f)); + REQUIRE(action0.iValue == 1000); + + Patch::action_t action1 = channel0.actions.at(1); + REQUIRE(action1.type == 2); + REQUIRE(action1.frame == 589); + REQUIRE(action1.fValue == Approx(1.0f)); + REQUIRE(action1.iValue == 130); + +#ifdef WITH_VST + Patch::plugin_t plugin0 = channel0.plugins.at(0); + REQUIRE(plugin0.path == "/path/to/plugin1"); + REQUIRE(plugin0.bypass == false); + REQUIRE(plugin0.params.at(0) == Approx(0.0f)); + REQUIRE(plugin0.params.at(1) == Approx(0.1f)); + REQUIRE(plugin0.params.at(2) == Approx(0.2f)); + + Patch::plugin_t plugin1 = channel0.plugins.at(1); + REQUIRE(plugin1.path == "/another/path/to/plugin2"); + REQUIRE(plugin1.bypass == true); + REQUIRE(plugin1.params.at(0) == Approx(0.6f)); + REQUIRE(plugin1.params.at(1) == Approx(0.6f)); + REQUIRE(plugin1.params.at(2) == Approx(0.6f)); + REQUIRE(plugin1.params.at(3) == Approx(0.0f)); + REQUIRE(plugin1.params.at(4) == Approx(1.0f)); + REQUIRE(plugin1.params.at(5) == Approx(1.0f)); + REQUIRE(plugin1.params.at(6) == Approx(0.333f)); + + Patch::plugin_t masterPlugin0 = patch.masterInPlugins.at(0); + REQUIRE(masterPlugin0.path == "/path/to/plugin1"); + REQUIRE(masterPlugin0.bypass == false); + REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f)); + REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f)); + REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f)); + + Patch::plugin_t masterPlugin1 = patch.masterOutPlugins.at(0); + REQUIRE(masterPlugin1.path == "/another/path/to/plugin2"); + REQUIRE(masterPlugin1.bypass == true); + REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f)); + REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f)); + REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f)); + REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f)); + REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f)); + REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f)); + REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f)); +#endif + } +} -- 2.30.2