compiler: gcc
-notifications:
+notifications:
email:
recipients:
- giadaloopmachine@gmail.com
- 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
+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)
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 \
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
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
# 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
@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 ------------------------------------------------------------------
# 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])
)
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],
#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;
/* -------------------------------------------------------------------------- */
-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");
}
/* -------------------------------------------------------------------------- */
-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; i<recorder::global.size; i++) {
+ for (unsigned k=0; k<recorder::global.at(i).size; k++) {
+ recorder::action *action = recorder::global.at(i).at(k);
+ if (action->chan == 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; i<numPlugs; i++) {
+ Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, PluginHost::CHANNEL, this);
+ if (pPlugin->status) {
+ Patch::plugin_t pp;
+ pp.path = pPlugin->pathfile;
+ pp.bypass = pPlugin->bypass;
+ for (int k=0; k<pPlugin->getNumParams(); 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; k<pch->actions.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; k<pch->plugins.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; j<ppl->params.size; j++)
+ plugin->setParam(j, ppl->params.at(j));
+ ret &= 1;
+ }
+ else
+ ret &= 0;
+ }
+
+#endif
+
+ return ret;
}
#endif
+using std::string;
+
+
class Channel {
protected:
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). */
* 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. */
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);
#include <limits.h>
#include <stdint.h>
-#include "dataStorage.h"
+#include "dataStorageIni.h"
#if defined(__APPLE__)
#endif
-class Conf : public DataStorage
+class Conf : public DataStorageIni
{
private:
*
* -------------------------------------------------------------------------- */
+
#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"
#define MAX_PATCHNAME_LEN 32
#define DB_MIN_SCALE 60.0f
#define MAX_VST_EVENTS 32
+#define MIN_COLUMN_WIDTH 140
#define DEFAULT_BARS 1
#define DEFAULT_QUANTIZE 0 // quantizer off
#define DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed
+#define DEFAULT_COLUMN_WIDTH 380
#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
#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
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * dataStorage
- *
- * -----------------------------------------------------------------------------
- *
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <stdlib.h>
-#include <limits.h>
-#include "../utils/log.h"
-#include "dataStorage.h"
-#include "const.h"
-
-
-std::string DataStorage::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. */
-
- fseek(fp, 0L, SEEK_SET);
- std::string out = "";
-
- while (!feof(fp)) {
-
- char buffer[MAX_LINE_LEN];
- if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) {
- gLog("[PATCH] get_value error (key=%s)\n", in);
- return "";
- }
-
- if (buffer[0] == '#')
- continue;
-
- unsigned len = strlen(in);
- if (strncmp(buffer, in, len) == 0) {
-
- for (unsigned i=len+1; i<MAX_LINE_LEN; i++) {
- if (buffer[i] == '\0' || buffer[i] == '\n' || buffer[i] == '\r')
- break;
- out += buffer[i];
- }
-
- break; // string found
- }
- }
- return out;
-}
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * dataStorage
- *
- * ---------------------------------------------------------------------
- *
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- * ------------------------------------------------------------------ */
-
-
-#ifndef __DATA_STORAGE_H__
-#define __DATA_STORAGE_H__
-
-#include <stdio.h>
-#include <string>
-#include <string.h>
-
-#define MAX_LINE_LEN 1024
-
-
-class DataStorage {
-
-protected:
-
- FILE *fp;
- std::string getValue(const char *in);
-};
-
-#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <limits.h>
+#include "../utils/log.h"
+#include "dataStorageIni.h"
+#include "const.h"
+
+
+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. */
+
+ fseek(fp, 0L, SEEK_SET);
+ std::string out = "";
+
+ while (!feof(fp)) {
+
+ char buffer[MAX_LINE_LEN];
+ if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) {
+ gLog("[DataStorageIni::getValue] key '%s' not found\n", in);
+ return "";
+ }
+
+ if (buffer[0] == '#')
+ continue;
+
+ unsigned len = strlen(in);
+ if (strncmp(buffer, in, len) == 0) {
+
+ for (unsigned i=len+1; i<MAX_LINE_LEN; i++) {
+ if (buffer[i] == '\0' || buffer[i] == '\n' || buffer[i] == '\r')
+ break;
+ out += buffer[i];
+ }
+
+ break; // string found
+ }
+ }
+ return out;
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __DATA_STORAGE_INI_H__
+#define __DATA_STORAGE_INI_H__
+
+#include <stdio.h>
+#include <string>
+#include <string.h>
+
+#define MAX_LINE_LEN 1024
+
+
+class DataStorageIni
+{
+protected:
+
+ FILE *fp;
+ std::string getValue(const char *in);
+};
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <string>
+#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;
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __DATA_STORAGE_JSON_H__
+#define __DATA_STORAGE_JSON_H__
+
+
+#include <stdint.h>
+#include <jansson.h>
+
+
+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
#include "wave.h"
#include "const.h"
#include "mixerHandler.h"
+#include "patch_DEPR_.h"
#include "patch.h"
#include "conf.h"
#include "pluginHost.h"
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;
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");
}
{
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);
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();
}
#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;
/* -------------------------------------------------------------------------- */
-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
}
/* -------------------------------------------------------------------------- */
+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) {
/* -------------------------------------------------------------------------- */
-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;
}
#endif
-class MidiChannel : public Channel {
-
+class MidiChannel : public Channel
+{
public:
MidiChannel(int bufferSize);
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);
/* ---------------------------------------------------------------- */
#include <limits.h>
#include <stdint.h>
-#include "dataStorage.h"
+#include "dataStorageIni.h"
#include "../utils/utils.h"
#if defined(__APPLE__)
#include <pwd.h>
using std::string;
-class MidiMapConf : public DataStorage
+class MidiMapConf : public DataStorageIni
{
private:
#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"
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
/* ------------------------------------------------------------------ */
-void Mixer::init() {
+void Mixer::init()
+{
quanto = 1;
docross = false;
rewindWait = false;
/* ------------------------------------------------------------------ */
-Channel *Mixer::addChannel(int type) {
-
+Channel *Mixer::addChannel(int type)
+{
Channel *ch;
int bufferSize = kernelAudio::realBufsize*2;
/* ------------------------------------------------------------------ */
-int Mixer::getNewIndex() {
-
+int Mixer::getNewIndex()
+{
/* always skip last channel: it's the last one just added */
if (channels.size == 1)
/* ------------------------------------------------------------------ */
-int Mixer::deleteChannel(Channel *ch) {
+int Mixer::deleteChannel(Channel *ch)
+{
int lockStatus;
while (true) {
lockStatus = pthread_mutex_trylock(&mutex_chans);
/* ------------------------------------------------------------------ */
-Channel *Mixer::getChannelByIndex(int index) {
+Channel *Mixer::getChannelByIndex(int index)
+{
for (unsigned i=0; i<channels.size; i++)
if (channels.at(i)->index == index)
return channels.at(i);
/* ------------------------------------------------------------------ */
-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);
/* ------------------------------------------------------------------ */
-void Mixer::sendMIDIrewind() {
-
+void Mixer::sendMIDIrewind()
+{
midiTCframes = 0;
midiTCseconds = 0;
midiTCminutes = 0;
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);
}
/* ------------------------------------------------------------------ */
-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;
/* ------------------------------------------------------------------ */
-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
/* ------------------------------------------------------------------ */
-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;
}
/* ------------------------------------------------------------------ */
-bool Mixer::isSilent() {
+bool Mixer::isSilent()
+{
for (unsigned i=0; i<channels.size; i++)
if (channels.at(i)->status == STATUS_PLAY)
return false;
/* ------------------------------------------------------------------ */
-void Mixer::rewind() {
-
+void Mixer::rewind()
+{
actualFrame = 0;
actualBeat = 0;
/* ------------------------------------------------------------------ */
-void Mixer::updateQuanto() {
-
+void Mixer::updateQuanto()
+{
/* big troubles if frames are odd. */
if (quantize != 0)
/* ------------------------------------------------------------------ */
-bool Mixer::hasLogicalSamples() {
+bool Mixer::hasLogicalSamples()
+{
for (unsigned i=0; i<channels.size; i++)
if (channels.at(i)->type == CHANNEL_SAMPLE)
if (((SampleChannel*)channels.at(i))->wave)
/* ------------------------------------------------------------------ */
-bool Mixer::hasEditedSamples() {
+bool Mixer::hasEditedSamples()
+{
for (unsigned i=0; i<channels.size; i++)
if (channels.at(i)->type == CHANNEL_SAMPLE)
if (((SampleChannel*)channels.at(i))->wave)
/* ------------------------------------------------------------------ */
-bool Mixer::mergeVirtualInput() {
+bool Mixer::mergeVirtualInput()
+{
if (vChanInput == NULL) {
gLog("[Mixer] virtual input channel not alloc'd\n");
return false;
#include "plugin.h"
#include "waveFx.h"
#include "conf.h"
+#include "patch_DEPR_.h"
#include "patch.h"
#include "recorder.h"
#include "channel.h"
#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
/* -------------------------------------------------------------------------- */
-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;
/** 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; i<numChans; i++) {
+ Channel *ch = glue_addChannel(G_Patch_DEPR_.getColumn(i), G_Patch_DEPR_.getType(i));
+ string samplePath = isProject ? projPath + gGetSlash() + G_Patch_DEPR_.getSamplePath(i) : "";
+ ch->readPatch_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;
}
/* 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 */
}
return true;
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+int __mh_readPatchPlugins__(gVector<Patch::plugin_t> *list, int type)
+{
+ int ret = 1;
+ for (unsigned i=0; i<list->size; 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; j<ppl->params.size; j++)
+ plugin->setParam(j, ppl->params.at(j));
+ ret &= 1;
+ }
+ else
+ ret &= 0;
+ }
+ return ret;
+}
+
+#endif
#include "recorder.h"
+#include "patch.h"
/* 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. */
* 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
bool mh_uniqueSamplename(class SampleChannel *ch, const char *name);
+#ifdef WITH_VST
+
+static int __mh_readPatchPlugins__(gVector<Patch::plugin_t> *list, int type);
+
+#endif
+
#endif
#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"
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;
}
/* -------------------------------------------------------------------------- */
-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<plugin_t> *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; j<plugins->size; 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<plugin.params.size; z++) {
+ json_array_append_new(jPluginParams, json_real(plugin.params.at(z)));
+ }
+ json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PARAMS, jPluginParams);
+ }
+ json_object_set_new(jContainer, key, jPlugins);
}
-
-/* -------------------------------------------------------------------------- */
-
-
-int Patch::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;
-}
+#endif
/* -------------------------------------------------------------------------- */
-int Patch::getEnd(int c, unsigned size)
+void Patch::writeColumns(json_t *jContainer, gVector<column_t> *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; i<columns->size; 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<action_t> *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; k<actions->size; 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<channel_t> *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; i<channels->size; 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<plugin_t> *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; i<numrecs; i++) {
- int frame, recPerFrame;
-
- /* parsing 'dddddd d': [framenumber] [num. recs for that frame] */
-
- char tmpbuf[16];
- sprintf(tmpbuf, "recframe%d", i);
- sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame);
-
-//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
-
- for (int k=0; k<recPerFrame; k++) {
- int chan = 0;
- int type = 0;
- float fValue = 0.0f;
- int iValue_fix = 0;
- uint32_t iValue = 0;
-
- /* reading info for each frame: %d|%d */
-
- char tmpbuf[16];
- sprintf(tmpbuf, "f%da%d", i, k);
-
- if (version < 0.61f) // no float and int values
- sscanf(getValue(tmpbuf).c_str(), "%d|%d", &chan, &type);
- else
- if (version < 0.83f) // iValues were stored as signed int (wrong)
- sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%d", &chan, &type, &fValue, &iValue_fix);
- else
- sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%u", &chan, &type, &fValue, &iValue);
-
-//gLog(" loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
-
- Channel *ch = G_Mixer.getChannelByIndex(chan);
- if (ch)
- if (ch->status & ~(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; i<G_Mixer.channels.size; i++) {
- Channel *ch = G_Mixer.channels.at(i);
-
- char tmp[MAX_LINE_LEN];
- sprintf(tmp, "chan%dPlugins", ch->index);
- int np = atoi(getValue(tmp).c_str());
-
- for (int j=0; j<np; j++) {
- sprintf(tmp, "chan%d_p%dpathfile", ch->index, 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; k<nparam; k++) {
- sprintf(tmp, "chan%d_p%dparam%dvalue", ch->index, 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; i<G_Mixer.channels.size; i++) {
- fprintf(fp, "# --- channel %d --- \n", i);
- G_Mixer.channels.at(i)->writePatch(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; i<recorder::global.size; i++) {
- fprintf(fp, "recframe%d=%d %d\n", i, recorder::frames.at(i), recorder::global.at(i).size);
- for (unsigned k=0; k<recorder::global.at(i).size; k++) {
- fprintf(fp, "f%da%d=%d|%d|%f|%u\n",
- i, k,
- recorder::global.at(i).at(k)->chan,
- 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; i<columns.size; i++) {
+ column_t *col = &columns.at(i);
+ col->index = 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; i<G_Mixer.channels.size; i++) {
- Channel *ch = G_Mixer.channels.at(i);
- numPlugs = G_PluginHost.countPlugins(PluginHost::CHANNEL, ch);
- fprintf(fp, "chan%dPlugins=%d\n", ch->index, numPlugs);
-
- for (int j=0; j<numPlugs; j++) {
- pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch);
- if (!pPlugin->status) {
- 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; k<numParams; k++)
- fprintf(fp, "chan%d_p%dparam%dvalue=%f\n", ch->index, j, k, pPlugin->getParam(k));
- }
- }
-
-#endif
-
- fclose(fp);
- return 1;
+ for (unsigned i=0; i<channels.size; i++) {
+ channel_t *ch = &channels.at(i);
+ ch->volume = 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; i<nmp; i++) {
- char tmp[MAX_LINE_LEN];
- sprintf(tmp, "master%c_p%dpathfile", chr, i);
- int out = G_PluginHost.addPlugin(getValue(tmp).c_str(), type);
- if (out != 0) {
- Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
- sprintf(tmp, "master%c_p%dbypass", chr, i);
- pPlugin->bypass = atoi(getValue(tmp).c_str());
- sprintf(tmp, "master%c_p%dnumParams", chr, i);
- int nparam = atoi(getValue(tmp).c_str());
- for (int j=0; j<nparam; j++) {
- sprintf(tmp, "master%c_p%dparam%dvalue", chr, i, j);
- float pval = atof(getValue(tmp).c_str());
- pPlugin->setParam(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; i<nmp; i++) {
-
- Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
- if (!pPlugin->status) {
- 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; j<numParams; j++)
- fprintf(fp, "master%c_p%dparam%dvalue=%f\n", chr, i, j, pPlugin->getParam(j));
- }
-}
-
-#endif
#ifndef __PATCH_H__
#define __PATCH_H__
-#include <stdio.h>
+
#include <string>
#include <stdint.h>
-#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<float> 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<action_t> actions;
+
+#ifdef WITH_VST
+ gVector<plugin_t> plugins;
+#endif
+ };
+
+ struct column_t
+ {
+ int index;
+ int width;
+ gVector<int> 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<column_t> columns;
+ gVector<channel_t> channels;
+
+#ifdef WITH_VST
+ gVector<plugin_t> masterInPlugins;
+ gVector<plugin_t> 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<plugin_t> *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<channel_t> *channels);
#ifdef WITH_VST
- int readPlugins();
+ void writePlugins (json_t *jContainer, gVector<plugin_t> *plugins, const char* key);
#endif
+ void writeActions (json_t *jContainer, gVector<action_t> *actions);
+ void writeColumns (json_t *jContainer, gVector<column_t> *columns);
};
#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <stdint.h>
+#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; i<numrecs; i++) {
+ int frame, recPerFrame;
+
+ /* parsing 'dddddd d': [framenumber] [num. recs for that frame] */
+
+ char tmpbuf[16];
+ sprintf(tmpbuf, "recframe%d", i);
+ sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame);
+
+//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame);
+
+ for (int k=0; k<recPerFrame; k++) {
+ int chan = 0;
+ int type = 0;
+ float fValue = 0.0f;
+ int iValue_fix = 0;
+ uint32_t iValue = 0;
+
+ /* reading info for each frame: %d|%d */
+
+ char tmpbuf[16];
+ sprintf(tmpbuf, "f%da%d", i, k);
+
+ if (version < 0.61f) // no float and int values
+ sscanf(getValue(tmpbuf).c_str(), "%d|%d", &chan, &type);
+ else
+ if (version < 0.83f) // iValues were stored as signed int (wrong)
+ sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%d", &chan, &type, &fValue, &iValue_fix);
+ else
+ sscanf(getValue(tmpbuf).c_str(), "%d|%d|%f|%u", &chan, &type, &fValue, &iValue);
+
+//gLog(" loading chan=%d, type=%d, fValue=%f, iValue=%u\n", chan, type, fValue, iValue);
+
+ Channel *ch = G_Mixer.getChannelByIndex(chan);
+ if (ch)
+ if (ch->status & ~(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; i<G_Mixer.channels.size; i++) {
+ Channel *ch = G_Mixer.channels.at(i);
+
+ char tmp[MAX_LINE_LEN];
+ sprintf(tmp, "chan%dPlugins", ch->index);
+ int np = atoi(getValue(tmp).c_str());
+
+ for (int j=0; j<np; j++) {
+ sprintf(tmp, "chan%d_p%dpathfile", ch->index, 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; k<nparam; k++) {
+ sprintf(tmp, "chan%d_p%dparam%dvalue", ch->index, 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; i<nmp; i++) {
+ char tmp[MAX_LINE_LEN];
+ sprintf(tmp, "master%c_p%dpathfile", chr, i);
+ Plugin *p = G_PluginHost.addPlugin(getValue(tmp).c_str(), type);
+ if (p != NULL) {
+ Plugin *pPlugin = G_PluginHost.getPluginByIndex(i, type);
+ sprintf(tmp, "master%c_p%dbypass", chr, i);
+ pPlugin->bypass = atoi(getValue(tmp).c_str());
+ sprintf(tmp, "master%c_p%dnumParams", chr, i);
+ int nparam = atoi(getValue(tmp).c_str());
+ for (int j=0; j<nparam; j++) {
+ sprintf(tmp, "master%c_p%dparam%dvalue", chr, i, j);
+ float pval = atof(getValue(tmp).c_str());
+ pPlugin->setParam(j, pval);
+ }
+ res &= 1;
+ }
+ else
+ res &= 0;
+ }
+
+ return res;
+}
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef __PATCH_DEPR_H__
+#define __PATCH_DEPR_H__
+
+#include <stdio.h>
+#include <string>
+#include <stdint.h>
+#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
/* 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. */
/* ------------------------------------------------------------------ */
-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;
if (!success) {
pStack->add(p);
- return 0;
+ return NULL;
}
/* otherwise let's try to initialize it. */
if (!p->init(&PluginHost::HostCallback)) {
delete p;
- return 0;
+ return NULL;
}
/* plugin setup */
p->resume();
- return 1;
+ return p;
}
}
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);
#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"
#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
#include <math.h>
#include "../utils/log.h"
#include "sampleChannel.h"
+#include "patch_DEPR_.h"
#include "patch.h"
#include "conf.h"
#include "wave.h"
#include "kernelMidi.h"
+extern Patch_DEPR_ G_Patch_DEPR_;
extern Patch G_Patch;
extern Mixer G_Mixer;
extern Conf G_Conf;
/* -------------------------------------------------------------------------- */
-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;
/* -------------------------------------------------------------------------- */
+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;
/* -------------------------------------------------------------------------- */
-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;
}
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
#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
/* -------------------------------------------------------------------------- */
-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;
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;
}
/* -------------------------------------------------------------------------- */
-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; i<G_Mixer.channels.size; i++) {
-
- if (G_Mixer.channels.at(i)->type == 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)
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,
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. */
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#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; i<G_Patch.columns.size; i++) {
+ Patch::column_t *col = &G_Patch.columns.at(i);
+ mainWin->keyboard->addColumn(col->width);
+ for (unsigned k=0; k<G_Patch.channels.size; k++) {
+ if (G_Patch.channels.at(k).column == col->index) {
+ 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 <Plugin *> *host, gVector<Patch::plugin_t> *patch)
+{
+ for (unsigned i=0; i<host->size; 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; k<numParams; k++)
+ ppl.params.add(pl->getParam(k));
+ patch->add(ppl);
+ }
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void __glue_fillPatchChannels__(bool isProject)
+{
+ for (unsigned i=0; i<G_Mixer.channels.size; i++) {
+ G_Mixer.channels.at(i)->writePatch(i, isProject);
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void __glue_fillPatchColumns__()
+{
+ for (unsigned i=0; i<mainWin->keyboard->getTotalColumns(); i++) {
+ gColumn *gCol = mainWin->keyboard->getColumn(i);
+ Patch::column_t pCol;
+ pCol.index = gCol->getIndex();
+ pCol.width = gCol->w();
+ for (unsigned k=0; k<gCol->countChannels(); k++) {
+ Channel *colChannel = gCol->getChannel(k);
+ for (unsigned j=0; j<G_Mixer.channels.size; j++) {
+ Channel *mixerChannel = G_Mixer.channels.at(j);
+ if (colChannel == mixerChannel) {
+ pCol.channels.add(mixerChannel->index);
+ 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; i<G_Mixer.channels.size; i++) {
+
+ if (G_Mixer.channels.at(i)->type == 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;
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#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 <Plugin *> *host, gVector<Patch::plugin_t> *patch);
+#endif
+
+static void __setProgressBar__(class gProgress *status, float v);
+
+#endif
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* gd_about
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
+#include <jansson.h>
#include "../../core/conf.h"
#include "../../core/const.h"
#include "../../core/kernelAudio.h"
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)
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;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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();
}
#include "../../utils/gui_utils.h"
-#include "../../core/patch.h"
#include "../../core/mixer.h"
#include "../../core/conf.h"
#include "../../glue/glue.h"
* 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.
#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"
#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;
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
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();
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.");
/* 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());
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());
}
/* -------------------------------------------------------------------------- */
-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!");
/* -------------------------------------------------------------------------- */
-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()))
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!");
#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"
#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;
#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"
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;
#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"
extern Mixer G_Mixer;
extern Conf G_Conf;
-extern Patch G_Patch;
+extern Patch_DEPR_ G_Patch_DEPR_;
extern gdMainWindow *mainWin;
#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("") {}
/* -------------------------------------------------------------------------- */
-void gChannelButton::setKey(const char *k)
+void gChannelButton::setKey(const string &k)
{
key = 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();
#include "ge_mixed.h"
+using std::string;
+
+
class gChannelButton : public gClick
{
private:
- std::string key;
+ string key;
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);
#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"
extern Mixer G_Mixer;
extern Conf G_Conf;
-extern Patch G_Patch;
+extern Patch_DEPR_ G_Patch_DEPR_;
extern gdMainWindow *mainWin;
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);
/* -------------------------------------------------------------------------- */
+
int gColumn::handle(int e)
{
switch (e) {
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
}
}
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+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;
+}
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
inline int getIndex() { return index; }
inline void setIndex(int i) { index = i; }
inline bool isEmpty() { return children() == 1; }
+ inline int countChannels() { return children(); }
};
#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"
extern Mixer G_Mixer;
extern Conf G_Conf;
-extern Patch G_Patch;
+extern Patch_DEPR_ G_Patch_DEPR_;
extern gdMainWindow *mainWin;
addColumnBtn->position(columns.last()->x() + columns.last()->w() + 16, y());
+ /* recompute col indexes */
+
+ refreshColIndexes();
+
redraw();
}
/* -------------------------------------------------------------------------- */
-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);
+}
/* -------------------------------------------------------------------------- */
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'. */
/* -------------------------------------------------------------------------- */
-gColumn *gKeyboard::getColumn(int index)
+gColumn *gKeyboard::getColumnByIndex(int index)
{
for (unsigned i=0; i<columns.size; i++)
if (columns.at(i)->getIndex() == index)
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; i<columns.size; i++)
+ columns.at(i)->setIndex(i);
}
#include <FL/Fl_Box.H>
#include <FL/Fl_Menu_Button.H>
#include "../elems/ge_column.h"
+#include "../../core/const.h"
#include "../../utils/utils.h"
{
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;
/* 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. */
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. */
* 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(); }
};
#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"
extern Mixer G_Mixer;
extern Conf G_Conf;
-extern Patch G_Patch;
+extern Patch_DEPR_ G_Patch_DEPR_;
extern gdMainWindow *mainWin;
solo->callback(cb_solo, (void*)this);
mainButton->callback(cb_openMenu, (void*)this);
+
vol->callback(cb_changeVol, (void*)this);
ch->guiChannel = this;
mute->value(ch->mute);
solo->value(ch->solo);
+ mainButton->setKey(ch->key);
+
#ifdef WITH_VST
fx->full = ch->plugins.size > 0;
#endif
#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"
extern Mixer G_Mixer;
extern Conf G_Conf;
-extern Patch G_Patch;
+extern Patch_DEPR_ G_Patch_DEPR_;
extern gdMainWindow *mainWin;
solo->callback(cb_solo, (void*)this);
mainButton->callback(cb_openMenu, (void*)this);
+
vol->callback(cb_changeVol, (void*)this);
ch->guiChannel = this;
mute->value(ch->mute);
solo->value(ch->solo);
+ mainButton->setKey(ch->key);
+
#ifdef WITH_VST
fx->full = ch->plugins.size > 0;
+ fx->redraw();
#endif
}
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) {
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) {
void addActionButton();
void delActionButton(bool force=false);
-
+
class gModeBox *modeBox;
class gClick *readActions;
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#include <pthread.h>
#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"
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
#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"
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;
void gu_updateControls()
{
- for (unsigned i=0; i<G_Mixer.channels.size; i++)
+ for (unsigned i=0; i<G_Mixer.channels.size; i++) {
G_Mixer.channels.at(i)->guiChannel->update();
+ }
mainWin->inOut->setOutVol(G_Mixer.outVol);
mainWin->inOut->setInVol(G_Mixer.inVol);
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());
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GVECTOR_H
+#define GVECTOR_H
+
+
+#include "log.h"
+
+
+/* gVector
+ * lightweight template class. */
+
+template <class T> 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<other.size; i++)
+ s[i] = other.s[i];
+ size = other.size;
+ }
+
+
+ ~gVector()
+ {
+ /// FIXME empty s with clear()?!?
+ }
+
+
+ void add(const T &item)
+ {
+ T *tmp = new T[size+1]; /// TODO: chunk increment (size+N), N ~= 16
+ for (unsigned i=0; i<size; i++)
+ tmp[i] = s[i];
+ tmp[size] = item;
+ delete[] s;
+ s = tmp;
+ size++;
+ }
+
+
+ int del(const T &item)
+ {
+ for (unsigned i=0; i<size; i++)
+ if (s[i] == item)
+ return del(i);
+ return -1;
+ }
+
+
+ int del(unsigned p)
+ {
+ if (p > 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<size) {
+ if (i != p) {
+ tmp[j] = s[i];
+ j++;
+ }
+ i++;
+ }
+ delete[] s;
+ s = tmp;
+ size -= 1;
+ return size;
+ }
+
+
+ void clear()
+ {
+ if (size > 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
#endif
+using std::string;
+
bool gFileExists(const char *filename) {
FILE *fh = fopen(filename, "rb");
* 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;
/* -------------------------------------------------------------------------- */
-
-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;
}
/* -------------------------------------------------------------------------- */
-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;
}
/* -------------------------------------------------------------------------- */
-std::string gGetCurrentPath()
+string gGetCurrentPath()
{
char buf[PATH_MAX];
#if defined(__WIN32)
/* -------------------------------------------------------------------------- */
-std::string gGetExt(const char *file)
+string gGetExt(const char *file)
{
int len = strlen(file);
int pos = len;
}
if (pos==0)
return "";
- std::string out = file;
+ string out = file;
return out.substr(pos+1, len);
}
/* -------------------------------------------------------------------------- */
-std::string gStripExt(const char *file)
+string gStripExt(const char *file)
{
int len = strlen(file);
int pos = -1;
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("."));
+}
+
+
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
-std::string gGetProjectName(const char *path)
+string gGetProjectName(const char *path)
{
- std::string out;
+ string out;
out = gStripExt(path);
int i = out.size();
/* -------------------------------------------------------------------------- */
-std::string gGetSlash() // TODO - create SLASH macro or constant
+string gGetSlash()
{
#if defined(_WIN32)
return "\\";
/* -------------------------------------------------------------------------- */
-std::string gItoa(int i)
+string gItoa(int i)
{
std::stringstream out;
out << 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");
/* -------------------------------------------------------------------------- */
-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();
}
/* -------------------------------------------------------------------------- */
-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;
/* -------------------------------------------------------------------------- */
-std::string gGetHomePath()
+string gGetHomePath()
{
char path[PATH_MAX];
#endif
- return std::string(path);
+ return string(path);
}
/* -------------------------------------------------------------------------- */
-void gSplit(std::string in, std::string sep, gVector<std::string> *v)
+void gSplit(string in, string sep, gVector<string> *v)
{
- std::string full = in;
- std::string token = "";
+ string full = in;
+ string token = "";
size_t curr = 0;
size_t next = -1;
do {
if (token != "")
v->add(token);
}
- while (next != std::string::npos);
+ while (next != string::npos);
}
#include <string>
#include <cstdio>
#include "log.h"
+#include "gvector.h"
-/* gVector
- * lightweight template class. */
-
-template <class T> 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<other.size; i++)
- s[i] = other.s[i];
- size = other.size;
- }
-
-
- ~gVector()
- {
- /// FIXME empty s with clear()?!?
- }
-
-
- void add(const T &item)
- {
- T *tmp = new T[size+1]; /// TODO: chunk increment (size+N), N ~= 16
- for (unsigned i=0; i<size; i++)
- tmp[i] = s[i];
- tmp[size] = item;
- delete[] s;
- s = tmp;
- size++;
- }
-
-
- int del(const T &item)
- {
- for (unsigned i=0; i<size; i++)
- if (s[i] == item)
- return del(i);
- return -1;
- }
-
-
- int del(unsigned p)
- {
- if (p > 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<size) {
- if (i != p) {
- tmp[j] = s[i];
- j++;
- }
- i++;
- }
- delete[] s;
- s = tmp;
- size -= 1;
- return size;
- }
-
-
- void clear()
- {
- if (size > 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);
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<std::string> *v);
+void gSplit(string in, string sep, gVector<string> *v);
#endif
--- /dev/null
+#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
+ }
+}