Imported Upstream version 0.10.0~dfsg1
authorJaromír Mikeš <mira.mikes@seznam.cz>
Tue, 7 Jul 2015 12:42:31 +0000 (14:42 +0200)
committerJaromír Mikeš <mira.mikes@seznam.cz>
Tue, 7 Jul 2015 12:42:31 +0000 (14:42 +0200)
37 files changed:
ChangeLog
configure.ac
src/Makefile.am
src/channel.cpp
src/channel.h
src/conf.cpp
src/conf.h
src/const.h
src/dataStorage.cpp
src/dataStorage.h
src/gd_browser.h
src/gd_config.cpp
src/gd_config.h
src/gd_mainWindow.cpp
src/gd_midiGrabber.cpp [deleted file]
src/gd_midiGrabber.h [deleted file]
src/gd_midiInput.cpp [new file with mode: 0644]
src/gd_midiInput.h [new file with mode: 0644]
src/gd_midiOutput.cpp [new file with mode: 0644]
src/gd_midiOutput.h [new file with mode: 0644]
src/gd_midiOutputSetup.cpp [deleted file]
src/gd_midiOutputSetup.h [deleted file]
src/ge_channel.cpp
src/ge_midiChannel.cpp
src/ge_midiIoTools.cpp [new file with mode: 0644]
src/ge_midiIoTools.h [new file with mode: 0644]
src/ge_sampleChannel.cpp
src/glue.cpp
src/init.cpp
src/init.h
src/kernelMidi.cpp
src/kernelMidi.h
src/main.cpp
src/midiChannel.cpp
src/midiMapConf.cpp [new file with mode: 0644]
src/midiMapConf.h [new file with mode: 0644]
src/sampleChannel.cpp

index 712ae50a6488ff5456c2c5d9efc3a78f2e0552cb..b662cd6b144c0ce724c7d0f1a7459b4db881edc6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
 
 
+0.10.0 --- 2015 . 07 . 05
+- MIDI lightning output
+- Other minor fixes
+
+
 0.9.6 --- 2015 . 05 . 11
 - Keyboard binding for MIDI channels
 - Support for multiple files in drag-n-drop operations
index 6ddcf0b3bf1069898e7855bfe4c3b8fae38f24da..5bb3b5979cae6f40aa978830bec36f5e6da15671 100644 (file)
@@ -4,7 +4,7 @@
 # prereq & init
 
 AC_PREREQ(2.60)
-AC_INIT([giada], [0.9], [giadaloopmachine@gmail.com])
+AC_INIT([giada], [0.10], [giadaloopmachine@gmail.com])
 AC_CONFIG_SRCDIR([src/main.cpp])
 AM_INIT_AUTOMAKE
 
index 644c35d3766a437ca5ad81ae3ac82fc3b59aa464..a717df4dcd1aa10734527c16ff91efb4dfeeded8 100644 (file)
@@ -37,11 +37,12 @@ gd_actionEditor.h      gd_actionEditor.cpp    ge_muteChannel.h     ge_muteChannel.
 ge_actionChannel.h   ge_actionChannel.cpp   gd_pluginWindowGUI.h gd_pluginWindowGUI.cpp \
 ge_actionWidget.h    ge_actionWidget.cpp    ge_envelopeChannel.h ge_envelopeChannel.cpp \
 ge_pianoRoll.h            ge_pianoRoll.cpp       kernelMidi.h         kernelMidi.cpp \
-gd_midiOutputSetup.h gd_midiOutputSetup.cpp gd_midiGrabber.h     gd_midiGrabber.cpp \
+gd_midiOutput.h      gd_midiOutput.cpp      gd_midiInput.h       gd_midiInput.cpp \
 sampleChannel.h      sampleChannel.cpp      midiChannel.cpp      midiChannel.h \
-ge_channel.h         ge_channel.cpp         log.h                log.cpp \
-ge_column.h          ge_column.cpp          ge_sampleChannel.h   ge_sampleChannel.cpp \
-ge_midiChannel.h     ge_midiChannel.cpp
+midiMapConf.cpp      midiMapConf.h          ge_channel.h         ge_channel.cpp \
+log.h                log.cpp                ge_column.h          ge_column.cpp \
+ge_sampleChannel.h   ge_sampleChannel.cpp   ge_midiChannel.h     ge_midiChannel.cpp \
+ge_midiIoTools.h     ge_midiIoTools.cpp
 
 
 
index f9a3b7cf3650330e3c0a3608d8a705e3c5777e4d..6c4c48e44ae90948bb082ceeb435f235ad64c4ef 100644 (file)
@@ -28,7 +28,6 @@
 
 
 #include "channel.h"
-#include "ge_channel.h"
 #include "pluginHost.h"
 #include "kernelMidi.h"
 #include "patch.h"
 #include "conf.h"
 #include "waveFx.h"
 #include "log.h"
+#include "midiMapConf.h"
+#include "ge_channel.h"
 
 
 extern Patch       G_Patch;
 extern Mixer       G_Mixer;
 extern Conf        G_Conf;
+extern MidiMapConf G_MidiMap;
 #ifdef WITH_VST
 extern PluginHost  G_PluginHost;
 #endif
@@ -66,13 +68,17 @@ Channel::Channel(int type, int status, int bufferSize)
          recStatus (REC_STOPPED),
          vChan     (NULL),
          guiChannel(NULL),
-         midiIn        (true),
-         midiInKeyPress(0x0),
-         midiInKeyRel  (0x0),
-         midiInKill    (0x0),
-         midiInVolume  (0x0),
-         midiInMute    (0x0),
-         midiInSolo    (0x0)
+         midiIn         (true),
+         midiInKeyPress (0x0),
+         midiInKeyRel   (0x0),
+         midiInKill     (0x0),
+         midiInVolume   (0x0),
+         midiInMute     (0x0),
+         midiInSolo     (0x0),
+         midiOutL       (false),
+         midiOutLplaying(0x0),
+         midiOutLmute   (0x0),
+         midiOutLsolo   (0x0)
 {
        vChan = (float *) malloc(bufferSize * sizeof(float));
        if (!vChan)
@@ -95,6 +101,29 @@ Channel::~Channel()
 /* -------------------------------------------------------------------------- */
 
 
+void Channel::sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset)
+{
+       gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
+               learn, chan, msg, offset);
+
+       uint32_t out;
+
+       /* isolate 'channel' from learnt message and offset it as requested by 'nn'
+        * in the midimap configuration file. */
+
+       out  = ((learn & 0x00FF0000) >> 16) << offset;
+
+       /* merge the previously prepared channel into final message, and finally
+        * send it. */
+
+       out |= msg | (chan << 24);
+       kernelMidi::send(out);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void Channel::readPatchMidiIn(int i)
 {
        midiIn         = G_Patch.getMidiValue(i, "In");
@@ -106,6 +135,14 @@ void Channel::readPatchMidiIn(int i)
   midiInSolo     = G_Patch.getMidiValue(i, "InSolo");
 }
 
+void Channel::readPatchMidiOut(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");
+}
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -138,4 +175,60 @@ void Channel::writePatch(FILE *fp, int i, bool isProject)
        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);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLmute()
+{
+       if (!midiOutL || midiOutLmute == 0x0)
+               return;
+       if (mute)
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOnChan, G_MidiMap.muteOnMsg, G_MidiMap.muteOnOffset);
+       else
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOffChan, G_MidiMap.muteOffMsg, G_MidiMap.muteOffOffset);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLsolo()
+{
+       if (!midiOutL || midiOutLsolo == 0x0)
+               return;
+       if (solo)
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOnChan, G_MidiMap.soloOnMsg, G_MidiMap.soloOnOffset);
+       else
+               sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOffChan, G_MidiMap.soloOffMsg, G_MidiMap.soloOffOffset);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::sendMidiLplay()
+{
+       if (!midiOutL || midiOutLplaying == 0x0)
+               return;
+       switch (status) {
+               case STATUS_OFF:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppedChan, G_MidiMap.stoppedMsg, G_MidiMap.stoppedOffset);
+                       break;
+               case STATUS_PLAY:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.playingChan, G_MidiMap.playingMsg, G_MidiMap.playingOffset);
+                       break;
+               case STATUS_WAIT:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.waitingChan, G_MidiMap.waitingMsg, G_MidiMap.waitingOffset);
+                       break;
+               case STATUS_ENDING:
+                       sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppingChan, G_MidiMap.stoppingMsg, G_MidiMap.stoppingOffset);
+       }
 }
index 6540fabfc3a9d87d2f993efff2d14b5065c588ab..fa34eac57dcb1bb8dc614a8a6cf39e75a59798f2 100644 (file)
@@ -61,6 +61,12 @@ protected:
 
        int bufferSize;
 
+       /* sendMidiLMessage
+        * compose a MIDI message by merging bytes from MidiMap conf class, and send
+        * it to KernelMidi. */
+
+       void sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset);
+
 public:
 
        Channel(int type, int status, int bufferSize);
@@ -164,7 +170,9 @@ public:
        float  *vChan;                // virtual channel
   class   gChannel *guiChannel; // pointer to a gChannel object, part of the GUI
 
-  bool     midiIn;              // enable midi output
+       // TODO - midi structs, please
+
+  bool     midiIn;              // enable midi input
   uint32_t midiInKeyPress;
   uint32_t midiInKeyRel;
   uint32_t midiInKill;
@@ -172,6 +180,16 @@ public:
   uint32_t midiInMute;
   uint32_t midiInSolo;
 
+       /*  midiOutL*
+        * Enable MIDI lightning output, plus a set of midi lighting event to be sent
+        * to a device. Those events basically contains the MIDI channel, everything
+        * else gets stripped out. */
+
+       bool     midiOutL;
+  uint32_t midiOutLplaying;
+  uint32_t midiOutLmute;
+  uint32_t midiOutLsolo;
+
 #ifdef WITH_VST
   gVector <class Plugin *> plugins;
 #endif
@@ -189,6 +207,14 @@ public:
         * and so on. */
 
        void readPatchMidiIn(int i);
+       void readPatchMidiOut(int i);
+
+       /* sendMidiL*
+        * send MIDI lightning events to a physical device. */
+
+       void sendMidiLmute();
+       void sendMidiLsolo();
+       void sendMidiLplay();
 };
 
 
index af1a4fec939028ab6c133c584a21633d98297c8c..fd6720ed4de4eb44da83870e21b1942eff4c3541 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * conf
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include <stdlib.h>
 
 int Conf::openFileForReading()
 {
-       char path[PATH_MAX];
-
-#if defined(__linux__)
-       snprintf(path, PATH_MAX, "%s/.giada/%s", getenv("HOME"), CONF_FILENAME);
-#elif defined(_WIN32)
-       snprintf(path, PATH_MAX, "%s", CONF_FILENAME);
-#elif defined(__APPLE__)
-       struct passwd *p = getpwuid(getuid());
-       if (p == NULL) {
-               gLog("[Conf::openFile] unable to fetch user infos\n");
-               return 0;
-       }
-       else {
-               const char *home = p->pw_dir;
-               snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada/giada.conf", home);
-       }
-#endif
-
-       fp = fopen(path, "r");
+       std::string path = gGetHomePath() + "/" + CONF_FILENAME;
+       fp = fopen(path.c_str(), "r");
        if (fp == NULL) {
                gLog("[Conf::openFile] unable to open conf file for reading\n");
                return 0;
@@ -63,7 +46,7 @@ int Conf::openFileForReading()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int Conf::createConfigFolder(const char *path)
@@ -84,7 +67,7 @@ int Conf::createConfigFolder(const char *path)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int Conf::openFileForWriting()
@@ -130,7 +113,7 @@ int Conf::openFileForWriting()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void Conf::setDefault()
@@ -146,11 +129,12 @@ void Conf::setDefault()
        limitOutput    = false;
        rsmpQuality    = 0;
 
-       midiPortIn  = DEFAULT_MIDI_PORT_IN;
-       noNoteOff   = false;
-       midiPortOut = DEFAULT_MIDI_PORT_OUT;
-       midiSync    = MIDI_SYNC_NONE;
-       midiTCfps   = 25.0f;
+       midiPortIn     = DEFAULT_MIDI_PORT_IN;
+       noNoteOff      = false;
+       midiMapPath[0] = '\0';
+       midiPortOut    = DEFAULT_MIDI_PORT_OUT;
+       midiSync       = MIDI_SYNC_NONE;
+       midiTCfps      = 25.0f;
 
        midiInRewind     = 0x0;
        midiInStartStop  = 0x0;
@@ -187,7 +171,7 @@ void Conf::setDefault()
 
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int Conf::read()
@@ -237,6 +221,14 @@ int Conf::read()
 
        noNoteOff = atoi(getValue("noNoteOff").c_str());
 
+       std::string tmpMidiMapPath = getValue("midiMapPath");
+       strncpy(midiMapPath, tmpMidiMapPath.c_str(), tmpMidiMapPath.size());
+       midiMapPath[tmpMidiMapPath.size()] = '\0';      // strncpy doesn't add '\0'
+
+       std::string tmplastFileMap = getValue("lastFileMap");
+       strncpy(lastFileMap, tmplastFileMap.c_str(), tmplastFileMap.size());
+       lastFileMap[tmplastFileMap.size()] = '\0';      // strncpy doesn't add '\0'
+
        midiSync  = atoi(getValue("midiSync").c_str());
        midiTCfps = atof(getValue("midiTCfps").c_str());
 
@@ -351,7 +343,7 @@ int Conf::read()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int Conf::write()
@@ -380,6 +372,8 @@ int Conf::write()
        fprintf(fp, "midiPortOut=%d\n", midiPortOut);
        fprintf(fp, "midiPortIn=%d\n",  midiPortIn);
        fprintf(fp, "noNoteOff=%d\n",   noNoteOff);
+       fprintf(fp, "midiMapPath=%s\n", midiMapPath);
+       fprintf(fp, "lastFileMap=%s\n", lastFileMap);
        fprintf(fp, "midiSync=%d\n",    midiSync);
        fprintf(fp, "midiTCfps=%f\n",   midiTCfps);
 
@@ -452,7 +446,7 @@ int Conf::write()
 
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void Conf::close()
@@ -462,7 +456,7 @@ void Conf::close()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void Conf::setPath(char *path, const char *p)
index 69ea8702cfa44c1f41cd2a5ec0d336f8f84c3a6c..9120f2ed4aec1dadd0bca167dc136cae275e7bf5 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * conf
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef __CONF_H__
@@ -68,6 +68,8 @@ public:
        int   midiPortOut;
        int   midiPortIn;
        bool  noNoteOff;
+       char  midiMapPath[FILENAME_MAX];
+       char  lastFileMap[FILENAME_MAX];
        int   midiSync;  // see const.h
        float midiTCfps;
 
index a0b51523fdb61cb0e0bf73cbed29e5e5b47a627b..9ada42e1a6a62fc0c4239792cc129f47f23961a8 100644 (file)
@@ -31,9 +31,9 @@
 
 
 /* -- version --------------------------------------------------------------- */
-#define VERSIONE                               "0.9.6"
+#define VERSIONE                               "0.10.0"
 #define VERSIONE_STR           "Giada"
-#define VERSIONE_FLOAT 0.96f
+#define VERSIONE_FLOAT 1.0f
 
 #define CONF_FILENAME          "giada.conf"
 
index 4704afc2d4d07248da460785e4dd5863d6d6251f..43729e8841bfc82417115f0ba8f59c65e3b6aaa9 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * dataStorage
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
+#include <stdlib.h>
+#include <limits.h>
 #include "dataStorage.h"
+#include "const.h"
 #include "log.h"
 
 
@@ -65,8 +68,3 @@ std::string DataStorage::getValue(const char *in) {
        }
        return out;
 }
-
-
-
-
-
index 4232b680d52656a49c1d756084a3f2d3c0ec8dea..9d54ddf40dbe24404e9afdb114f08c26236a0022 100644 (file)
@@ -43,7 +43,6 @@ protected:
 
        FILE *fp;
        std::string getValue(const char *in);
-
 };
 
 #endif
index b5e8734050275a57baa27e0fd8ecbc928a6d7565..61f482ddc2142cc7437b569418f78a8aeebc9cf9 100644 (file)
@@ -90,9 +90,13 @@ private:
 
        int stackType;
 
+       char selectedFile[FILENAME_MAX];
+
 public:
        gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0);
        ~gdBrowser();
+
+       char* SelectedFile();
 };
 
 #endif
index 54f2627d90c9cc6b439163e01a3f9360c7da7bff..ab34fc6c7e616ed9f0d021b5e21a3d4017f85528 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * gd_config
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include "gd_config.h"
 #include "gd_keyGrabber.h"
 #include "gd_devInfo.h"
+#include "gd_browser.h"
 #include "ge_mixed.h"
 #include "conf.h"
+#include "midiMapConf.h"
 #include "log.h"
 #include "gui_utils.h"
 #include "patch.h"
 extern Patch G_Patch;
 extern Conf     G_Conf;
 extern bool  G_audio_status;
+extern MidiMapConf G_MidiMap;
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 gTabMisc::gTabMisc(int X, int Y, int W, int H)
@@ -74,7 +77,7 @@ gTabMisc::gTabMisc(int X, int Y, int W, int H)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMisc::save()
@@ -93,9 +96,9 @@ void gTabMisc::save()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gTabAudio::gTabAudio(int X, int Y, int W, int H)
@@ -216,7 +219,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_deactivate_sounddev(); }
@@ -226,7 +229,7 @@ void gTabAudio::cb_showInputInfo(Fl_Widget *w, void *p)       { ((gTabAudio*)p)-
 void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p)      { ((gTabAudio*)p)->__cb_showOutputInfo(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::__cb_fetchInChans()
@@ -236,7 +239,7 @@ void gTabAudio::__cb_fetchInChans()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::__cb_fetchOutChans()
@@ -246,7 +249,7 @@ void gTabAudio::__cb_fetchOutChans()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::__cb_showInputInfo()
@@ -256,7 +259,7 @@ void gTabAudio::__cb_showInputInfo()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::__cb_showOutputInfo()
@@ -266,7 +269,7 @@ void gTabAudio::__cb_showOutputInfo()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::__cb_deactivate_sounddev()
@@ -309,7 +312,7 @@ void gTabAudio::__cb_deactivate_sounddev()
        }
 }
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::fetchInChans(int menuItem)
@@ -346,7 +349,7 @@ void gTabAudio::fetchInChans(int menuItem)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::fetchOutChans(int menuItem)
@@ -370,7 +373,7 @@ void gTabAudio::fetchOutChans(int menuItem)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int gTabAudio::findMenuDevice(gChoice *m, int device)
@@ -394,7 +397,7 @@ int gTabAudio::findMenuDevice(gChoice *m, int device)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::fetchSoundDevs()
@@ -462,7 +465,7 @@ void gTabAudio::fetchSoundDevs()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabAudio::save()
@@ -512,9 +515,9 @@ void gTabAudio::save()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gTabMidi::gTabMidi(int X, int Y, int W, int H)
@@ -525,7 +528,8 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H)
        portOut   = new gChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port");
        portIn    = new gChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port");
        noNoteOff = new gCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff");
-       sync        = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Sync");
+       midiMap   = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map");
+       sync        = new gChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync");
        new gBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect.");
        end();
 
@@ -536,6 +540,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H)
        fetchSystems();
        fetchOutPorts();
        fetchInPorts();
+       fetchMidiMaps();
 
        noNoteOff->value(G_Conf.noNoteOff);
 
@@ -553,7 +558,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::fetchOutPorts() {
@@ -579,7 +584,7 @@ void gTabMidi::fetchOutPorts() {
        }
 }
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::fetchInPorts()
@@ -606,7 +611,27 @@ void gTabMidi::fetchInPorts()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+
+
+void gTabMidi::fetchMidiMaps()
+{
+       if (G_MidiMap.maps.size == 0) {
+               midiMap->add("(no MIDI maps available)");
+               midiMap->value(0);
+               midiMap->deactivate();
+               return;
+       }
+       for (unsigned i=0; i<G_MidiMap.maps.size; i++) {
+               const char *imap = G_MidiMap.maps.at(i).c_str();
+               midiMap->add(imap);
+               if (strcmp(G_Conf.midiMapPath, imap) == 0)
+                       midiMap->value(i);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::save()
@@ -617,8 +642,6 @@ void gTabMidi::save()
                G_Conf.midiSystem = RtMidi::UNIX_JACK;
        else if (!strcmp("Multimedia MIDI", system->text(system->value())))
                G_Conf.midiSystem = RtMidi::WINDOWS_MM;
-       //else if (!strcmp("Kernel Streaming MIDI", system->text(system->value())))
-       //      G_Conf.midiSystem = RtMidi::WINDOWS_KS;
        else if (!strcmp("OSX Core MIDI", system->text(system->value())))
                G_Conf.midiSystem = RtMidi::MACOSX_CORE;
 
@@ -627,6 +650,8 @@ void gTabMidi::save()
 
        G_Conf.noNoteOff   = noNoteOff->value();
 
+       G_Conf.setPath(G_Conf.midiMapPath, midiMap->text(midiMap->value()));
+
        if      (sync->value() == 0)
                G_Conf.midiSync = MIDI_SYNC_NONE;
        else if (sync->value() == 1)
@@ -636,7 +661,7 @@ void gTabMidi::save()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::fetchSystems()
@@ -652,8 +677,6 @@ void gTabMidi::fetchSystems()
 
        if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM))
                system->add("Multimedia MIDI");
-       //if (kernelMidi::hasAPI(RtMidi::WINDOWS_KS))
-       //      system->add("Kernel Streaming MIDI");
 
 #elif defined (__APPLE__)
 
@@ -665,20 +688,19 @@ void gTabMidi::fetchSystems()
                case RtMidi::LINUX_ALSA:  system->show("ALSA"); break;
                case RtMidi::UNIX_JACK:   system->show("Jack"); break;
                case RtMidi::WINDOWS_MM:  system->show("Multimedia MIDI"); break;
-               //case RtMidi::WINDOWS_KS:  system->show("Kernel Streaming MIDI"); break;
                case RtMidi::MACOSX_CORE: system->show("OSX Core MIDI"); break;
                default: system->value(0); break;
        }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((gTabMidi*)p)->__cb_changeSystem(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabMidi::__cb_changeSystem()
@@ -702,9 +724,9 @@ void gTabMidi::__cb_changeSystem()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H)
@@ -739,13 +761,13 @@ gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabBehaviors::cb_radio_mutex(Fl_Widget *w, void *p) { ((gTabBehaviors*)p)->__cb_radio_mutex(w); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w)
@@ -754,7 +776,7 @@ void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gTabBehaviors::save()
@@ -765,9 +787,9 @@ void gTabBehaviors::save()
 }
 
 
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 
 gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration")
@@ -802,7 +824,7 @@ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration")
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 gdConfig::~gdConfig()
@@ -812,14 +834,14 @@ gdConfig::~gdConfig()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdConfig::cb_save_config(Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_save_config(); }
 void gdConfig::cb_cancel     (Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_cancel(); }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdConfig::__cb_save_config()
@@ -832,7 +854,7 @@ void gdConfig::__cb_save_config()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void gdConfig::__cb_cancel()
index 1cfc20260a0d509ce137f594a25f2e7bbe63c3ed..fa28b80f2c498ba47b1f6298e099a6123aaa959c 100644 (file)
@@ -35,7 +35,7 @@
 #include "ge_window.h"
 
 
-class gdConfig : public gWindow 
+class gdConfig : public gWindow
 {
 private:
        static void cb_save_config        (Fl_Widget *w, void *p);
@@ -59,12 +59,14 @@ public:
 /* ------------------------------------------------------------------ */
 
 
-class gTabMidi : public Fl_Group 
+class gTabMidi : public Fl_Group
 {
 private:
+
        void fetchSystems();
        void fetchOutPorts();
        void fetchInPorts();
+       void fetchMidiMaps();
 
        static void cb_changeSystem  (Fl_Widget *w, void *p);
        inline void __cb_changeSystem();
@@ -72,10 +74,12 @@ private:
        int systemInitValue;
 
 public:
+       
        class gChoice *system;
        class gChoice *portOut;
        class gChoice *portIn;
        class gCheck  *noNoteOff;
+       class gChoice *midiMap;
        class gChoice *sync;
 
        gTabMidi(int x, int y, int w, int h);
@@ -87,7 +91,7 @@ public:
 /* ------------------------------------------------------------------ */
 
 
-class gTabAudio : public Fl_Group 
+class gTabAudio : public Fl_Group
 {
 private:
        static void cb_deactivate_sounddev(Fl_Widget *w, void *p);
@@ -131,7 +135,7 @@ public:
 /* ------------------------------------------------------------------ */
 
 
-class gTabBehaviors : public Fl_Group 
+class gTabBehaviors : public Fl_Group
 {
 private:
        static void cb_radio_mutex  (Fl_Widget *w, void *p);
@@ -153,10 +157,10 @@ public:
 /* ------------------------------------------------------------------ */
 
 
-class gTabMisc : public Fl_Group 
+class gTabMisc : public Fl_Group
 {
 public:
-       class gChoice *debugMsg;        
+       class gChoice *debugMsg;
 
        gTabMisc(int x, int y, int w, int h);
 
index 45ebccba94229a8543e230cc4b3f45b20ff7477e..b8fc2dfb590d935b45f940b6011f187e5c9750ed 100644 (file)
@@ -35,7 +35,7 @@
 #include "gd_warnings.h"
 #include "gd_bpmInput.h"
 #include "gd_beatsInput.h"
-#include "gd_midiGrabber.h"
+#include "gd_midiInput.h"
 #include "gg_keyboard.h"
 #include "gd_about.h"
 #include "gd_config.h"
@@ -413,7 +413,7 @@ void gMenu::__cb_edit()
                return;
        }
        if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiGrabberMaster(), 0);
+               gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0);
                return;
        }
 }
diff --git a/src/gd_midiGrabber.cpp b/src/gd_midiGrabber.cpp
deleted file mode 100644 (file)
index 18a9c3c..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiGrabber
- *
- * ---------------------------------------------------------------------
- *
- * 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 "gd_midiGrabber.h"
-#include "ge_mixed.h"
-#include "gui_utils.h"
-#include "kernelMidi.h"
-#include "conf.h"
-#include "sampleChannel.h"
-#include "log.h"
-
-
-extern Conf G_Conf;
-
-
-gdMidiGrabber::gdMidiGrabber(int w, int h, const char *title)
-       : gWindow(w, h, title)
-{
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdMidiGrabber::~gdMidiGrabber() {
-       kernelMidi::stopMidiLearn();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabber::stopMidiLearn(gLearner *learner) {
-       kernelMidi::stopMidiLearn();
-       learner->updateValue();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabber::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
-       *param = msg;
-       stopMidiLearn(l);
-       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabber::cb_learn(uint32_t msg, void *d) {
-       cbData *data = (cbData*) d;
-       gdMidiGrabber *grabber = (gdMidiGrabber*) data->grabber;
-       gLearner      *learner = data->learner;
-       uint32_t      *param   = learner->param;
-       grabber->__cb_learn(param, msg, learner);
-       free(data);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabber::cb_close(Fl_Widget *w, void *p)  { ((gdMidiGrabber*)p)->__cb_close(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabber::__cb_close() {
-       do_callback();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gdMidiGrabberChannel::gdMidiGrabberChannel(Channel *ch)
-       :       gdMidiGrabber(300, 206, "MIDI Input Setup"),
-               ch(ch)
-{
-       char title[64];
-       sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1);
-       label(title);
-
-       set_modal();
-
-       enable = new gCheck(8, 8, 120, 20, "enable MIDI input");
-       new gLearner(8,  30, w()-16, "key press",   cb_learn, &ch->midiInKeyPress);
-       new gLearner(8,  54, w()-16, "key release", cb_learn, &ch->midiInKeyRel);
-       new gLearner(8,  78, w()-16, "key kill",    cb_learn, &ch->midiInKill);
-       new gLearner(8, 102, w()-16, "mute",        cb_learn, &ch->midiInMute);
-       new gLearner(8, 126, w()-16, "solo",        cb_learn, &ch->midiInSolo);
-       new gLearner(8, 150, w()-16, "volume",      cb_learn, &ch->midiInVolume);
-       int yy = 178;
-
-       if (ch->type == CHANNEL_SAMPLE) {
-               size(300, 254);
-               new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
-               new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
-               yy = 226;
-       }
-
-       ok = new gButton(w()-88, yy, 80, 20, "Ok");
-       ok->callback(cb_close, (void*)this);
-
-       enable->value(ch->midiIn);
-       enable->callback(cb_enable, (void*)this);
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabberChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiGrabberChannel*)p)->__cb_enable(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiGrabberChannel::__cb_enable() {
-       ch->midiIn = enable->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gdMidiGrabberMaster::gdMidiGrabberMaster()
-       : gdMidiGrabber(300, 256, "MIDI Input Setup (global)")
-{
-       set_modal();
-
-       new gLearner(8,   8, w()-16, "rewind",           &cb_learn, &G_Conf.midiInRewind);
-       new gLearner(8,  32, w()-16, "play/stop",        &cb_learn, &G_Conf.midiInStartStop);
-       new gLearner(8,  56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec);
-       new gLearner(8,  80, w()-16, "input recording",  &cb_learn, &G_Conf.midiInInputRec);
-       new gLearner(8, 104, w()-16, "metronome",        &cb_learn, &G_Conf.midiInMetronome);
-       new gLearner(8, 128, w()-16, "input volume",     &cb_learn, &G_Conf.midiInVolumeIn);
-       new gLearner(8, 152, w()-16, "output volume",    &cb_learn, &G_Conf.midiInVolumeOut);
-       new gLearner(8, 176, w()-16, "sequencer ×2",     &cb_learn, &G_Conf.midiInBeatDouble);
-       new gLearner(8, 200, w()-16, "sequencer ÷2",     &cb_learn, &G_Conf.midiInBeatHalf);
-       ok = new gButton(w()-88, 228, 80, 20, "Ok");
-
-       ok->callback(cb_close, (void*)this);
-
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-
-
-gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param)
-       : Fl_Group(X, Y, W, 20),
-               callback(cb),
-               param   (param)
-{
-       begin();
-       text   = new gBox(x(), y(), 156, 20, l);
-       value  = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)");
-       button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn");
-       end();
-
-       text->box(G_BOX);
-       text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-
-       value->box(G_BOX);
-       value->callback(cb_value, (void*)this);
-       value->when(FL_WHEN_RELEASE);
-       updateValue();
-
-       button->type(FL_TOGGLE_BUTTON);
-       button->callback(cb_button, (void*)this);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLearner::updateValue() {
-       char buf[16];
-       if (*param != 0x0)
-               snprintf(buf, 9, "0x%X", *param);
-       else
-               snprintf(buf, 16, "(not set)");
-       value->copy_label(buf);
-       button->value(0);
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); }
-void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLearner::__cb_value() {
-       if (Fl::event_button() == FL_RIGHT_MOUSE) {
-               *param = 0x0;
-               updateValue();
-       }
-       /// TODO - elif (LEFT_MOUSE) : insert values by hand
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gLearner::__cb_button() {
-       if (button->value() == 1) {
-               cbData *data  = (cbData*) malloc(sizeof(cbData));
-               data->grabber = (gdMidiGrabber*) parent();  // parent = gdMidiGrabberChannel
-               data->learner = this;
-               kernelMidi::startMidiLearn(callback, (void*)data);
-       }
-       else
-               kernelMidi::stopMidiLearn();
-}
-
diff --git a/src/gd_midiGrabber.h b/src/gd_midiGrabber.h
deleted file mode 100644 (file)
index 4da9e72..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiGrabber
- *
- * ---------------------------------------------------------------------
- *
- * 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 GD_MIDIGRABBER_H
-#define GD_MIDIGRABBER_H
-
-
-#include "ge_window.h"
-#include "kernelMidi.h"
-#include "utils.h"
-#include "ge_mixed.h"
-
-
-class gLearner : public Fl_Group {
-
-private:
-
-       /* callback
-        * cb to pass to kernelMidi. Requires two parameters:
-        * uint32_t msg - MIDI message
-        * void   *data - extra data */
-
-       kernelMidi::cb_midiLearn *callback;
-
-       class gBox    *text;
-       class gClick  *value;
-       class gButton *button;
-
-       static void cb_button(Fl_Widget *v, void *p);
-       static void cb_value (Fl_Widget *v, void *p);
-       inline void __cb_button();
-       inline void __cb_value();
-
-public:
-
-       /* param
-        * pointer to ch->midiIn[value] */
-
-       uint32_t *param;
-
-       gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param);
-
-       void updateValue();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gdMidiGrabber : public gWindow {
-
-protected:
-
-       gClick *ok;
-
-       void stopMidiLearn(gLearner *l);
-
-       /* cb_learn
-        * callback attached to kernelMidi to learn various actions. */
-
-       static void cb_learn  (uint32_t msg, void *data);
-       inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l);
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
-
-public:
-
-       gdMidiGrabber(int w, int h, const char *title);
-       ~gdMidiGrabber();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gdMidiGrabberChannel : public gdMidiGrabber {
-
-private:
-
-       class Channel *ch;
-
-       gCheck *enable;
-
-
-       //gVector <gLearner *> items; for future use, with vst parameters
-
-       static void cb_enable  (Fl_Widget *w, void *p);
-       inline void __cb_enable();
-
-public:
-
-       gdMidiGrabberChannel(class Channel *ch);
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-class gdMidiGrabberMaster : public gdMidiGrabber {
-
-public:
-
-       gdMidiGrabberMaster();
-};
-
-
-/* ------------------------------------------------------------------ */
-
-
-/* cbData
- * struct we pass to kernelMidi as extra parameter. Local scope made
- * with unnamed namespace. Infos:
- * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */
-
-namespace {
-       struct cbData {
-               gdMidiGrabber *grabber;
-               gLearner      *learner;
-       };
-}
-
-
-#endif
diff --git a/src/gd_midiInput.cpp b/src/gd_midiInput.cpp
new file mode 100644 (file)
index 0000000..5d41ae1
--- /dev/null
@@ -0,0 +1,184 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiInput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "gd_midiInput.h"
+#include "ge_mixed.h"
+#include "ge_midiIoTools.h"
+#include "gui_utils.h"
+#include "kernelMidi.h"
+#include "conf.h"
+#include "sampleChannel.h"
+#include "log.h"
+
+
+extern Conf G_Conf;
+
+
+gdMidiInput::gdMidiInput(int w, int h, const char *title)
+       : gWindow(w, h, title)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInput::~gdMidiInput() {
+       kernelMidi::stopMidiLearn();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::stopMidiLearn(gLearner *learner) {
+       kernelMidi::stopMidiLearn();
+       learner->updateValue();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+       *param = msg;
+       stopMidiLearn(l);
+       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::cb_learn(uint32_t msg, void *d) {
+       cbData *data = (cbData*) d;
+       gdMidiInput   *window  = (gdMidiInput*) data->window;
+       gLearner      *learner = data->learner;
+       uint32_t      *param   = learner->param;
+       window->__cb_learn(param, msg, learner);
+       free(data);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiInput*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInput::__cb_close() {
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
+       :       gdMidiInput(300, 206, "MIDI Input Setup"),
+               ch(ch)
+{
+       char title[64];
+       sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1);
+       label(title);
+
+       set_modal();
+
+       enable = new gCheck(8, 8, 120, 20, "enable MIDI input");
+       new gLearner(8,  30, w()-16, "key press",   cb_learn, &ch->midiInKeyPress);
+       new gLearner(8,  54, w()-16, "key release", cb_learn, &ch->midiInKeyRel);
+       new gLearner(8,  78, w()-16, "key kill",    cb_learn, &ch->midiInKill);
+       new gLearner(8, 102, w()-16, "mute",        cb_learn, &ch->midiInMute);
+       new gLearner(8, 126, w()-16, "solo",        cb_learn, &ch->midiInSolo);
+       new gLearner(8, 150, w()-16, "volume",      cb_learn, &ch->midiInVolume);
+       int yy = 178;
+
+       if (ch->type == CHANNEL_SAMPLE) {
+               size(300, 254);
+               new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
+               new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
+               yy = 226;
+       }
+
+       ok = new gButton(w()-88, yy, 80, 20, "Close");
+       ok->callback(cb_close, (void*)this);
+
+       enable->value(ch->midiIn);
+       enable->callback(cb_enable, (void*)this);
+
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiInputChannel*)p)->__cb_enable(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputChannel::__cb_enable() {
+       ch->midiIn = enable->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiInputMaster::gdMidiInputMaster()
+       : gdMidiInput(300, 256, "MIDI Input Setup (global)")
+{
+       set_modal();
+
+       new gLearner(8,   8, w()-16, "rewind",           &cb_learn, &G_Conf.midiInRewind);
+       new gLearner(8,  32, w()-16, "play/stop",        &cb_learn, &G_Conf.midiInStartStop);
+       new gLearner(8,  56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec);
+       new gLearner(8,  80, w()-16, "input recording",  &cb_learn, &G_Conf.midiInInputRec);
+       new gLearner(8, 104, w()-16, "metronome",        &cb_learn, &G_Conf.midiInMetronome);
+       new gLearner(8, 128, w()-16, "input volume",     &cb_learn, &G_Conf.midiInVolumeIn);
+       new gLearner(8, 152, w()-16, "output volume",    &cb_learn, &G_Conf.midiInVolumeOut);
+       new gLearner(8, 176, w()-16, "sequencer ×2",     &cb_learn, &G_Conf.midiInBeatDouble);
+       new gLearner(8, 200, w()-16, "sequencer ÷2",     &cb_learn, &G_Conf.midiInBeatHalf);
+       ok = new gButton(w()-88, 228, 80, 20, "Close");
+
+       ok->callback(cb_close, (void*)this);
+
+       gu_setFavicon(this);
+       show();
+}
diff --git a/src/gd_midiInput.h b/src/gd_midiInput.h
new file mode 100644 (file)
index 0000000..91bdea1
--- /dev/null
@@ -0,0 +1,98 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiInput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 GD_MIDI_INPUT_H
+#define GD_MIDI_INPUT_H
+
+
+#include "ge_window.h"
+#include "kernelMidi.h"
+#include "utils.h"
+#include "ge_mixed.h"
+
+
+class gdMidiInput : public gWindow
+{
+protected:
+
+       gClick *ok;
+
+       void stopMidiLearn(class gLearner *l);
+
+       /* cb_learn
+        * callback attached to kernelMidi to learn various actions. */
+
+       static void cb_learn  (uint32_t msg, void *data);
+       inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l);
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+public:
+
+       gdMidiInput(int w, int h, const char *title);
+       ~gdMidiInput();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiInputChannel : public gdMidiInput
+{
+private:
+
+       class Channel *ch;
+
+       gCheck *enable;
+
+
+       //gVector <gLearner *> items; for future use, with vst parameters
+
+       static void cb_enable  (Fl_Widget *w, void *p);
+       inline void __cb_enable();
+
+public:
+
+       gdMidiInputChannel(class Channel *ch);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiInputMaster : public gdMidiInput
+{
+public:
+
+       gdMidiInputMaster();
+};
+
+
+#endif
diff --git a/src/gd_midiOutput.cpp b/src/gd_midiOutput.cpp
new file mode 100644 (file)
index 0000000..b01f6f6
--- /dev/null
@@ -0,0 +1,249 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiOutput
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "gd_midiOutput.h"
+#include "ge_mixed.h"
+#include "ge_channel.h"
+#include "ge_midiIoTools.h"
+#include "gg_keyboard.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "conf.h"
+#include "midiChannel.h"
+#include "gui_utils.h"
+
+
+extern Conf    G_Conf;
+
+
+gdMidiOutput::gdMidiOutput(int w, int h)
+       //: gWindow(300, 64, "Midi Output Setup")
+       : gWindow(w, h, "Midi Output Setup")
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::stopMidiLearn(gLearner *learner) {
+       kernelMidi::stopMidiLearn();
+       learner->updateValue();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) {
+       *param = msg;
+       stopMidiLearn(l);
+       gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_learn(uint32_t msg, void *d) {
+       cbData *data = (cbData*) d;
+       gdMidiOutput  *window  = (gdMidiOutput*) data->window;
+       gLearner      *learner = data->learner;
+       uint32_t      *param   = learner->param;
+       window->__cb_learn(param, msg, learner);
+       free(data);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_close(Fl_Widget *w, void *p)  { ((gdMidiOutput*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_close() {
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p)  {
+       ((gdMidiOutput*)p)->__cb_enableLightning();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::__cb_enableLightning() {}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutput::setTitle(int chanNum)
+{
+       char title[64];
+       sprintf(title, "MIDI Output Setup (channel %d)", chanNum);
+       copy_label(title);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch)
+       : gdMidiOutput(300, 168), ch(ch)
+{
+       setTitle(ch->index+1);
+       begin();
+
+       enableOut   = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output");
+       chanListOut = new gChoice(w()-108, y()+8, 100, 20);
+
+       enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output");
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+8,  w()-16, "playing", cb_learn, &ch->midiOutLplaying);
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",    cb_learn, &ch->midiOutLmute);
+       new gLearner(x()+8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",    cb_learn, &ch->midiOutLsolo);
+
+       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
+
+       end();
+
+       chanListOut->add("Channel 1");
+       chanListOut->add("Channel 2");
+       chanListOut->add("Channel 3");
+       chanListOut->add("Channel 4");
+       chanListOut->add("Channel 5");
+       chanListOut->add("Channel 6");
+       chanListOut->add("Channel 7");
+       chanListOut->add("Channel 8");
+       chanListOut->add("Channel 9");
+       chanListOut->add("Channel 10");
+       chanListOut->add("Channel 11");
+       chanListOut->add("Channel 12");
+       chanListOut->add("Channel 13");
+       chanListOut->add("Channel 14");
+       chanListOut->add("Channel 15");
+       chanListOut->add("Channel 16");
+       chanListOut->value(0);
+
+       if (ch->midiOut)
+               enableOut->value(1);
+       else
+               chanListOut->deactivate();
+
+       if (ch->midiOutL)
+               enableLightning->value(1);
+
+       chanListOut->value(ch->midiOutChan);
+
+       enableOut->callback(cb_enableChanList, (void*)this);
+       close->callback(cb_close, (void*)this);
+
+       set_modal();
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::cb_close         (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); }
+void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::__cb_enableChanList() {
+       enableOut->value() ? chanListOut->activate() : chanListOut->deactivate();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputMidiCh::__cb_close() {
+       ch->midiOut     = enableOut->value();
+       ch->midiOutChan = chanListOut->value();
+       ch->midiOutL    = enableLightning->value();
+       ch->guiChannel->update();
+       do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch)
+       : gdMidiOutput(300, 140), ch(ch)
+{
+       setTitle(ch->index+1);
+
+       enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output");
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying);
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+32, w()-16, "mute",   cb_learn, &ch->midiOutLmute);
+       new gLearner(8,  enableLightning->y()+enableLightning->h()+56, w()-16, "solo",   cb_learn, &ch->midiOutLsolo);
+
+       close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
+       close->callback(cb_close, (void*)this);
+
+       enableLightning->value(ch->midiOutL);
+       enableLightning->callback(cb_enableLightning, (void*)this);
+
+       set_modal();
+       gu_setFavicon(this);
+       show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiOutputSampleCh::__cb_close() {
+       ch->midiOutL = enableLightning->value();
+       do_callback();
+}
diff --git a/src/gd_midiOutput.h b/src/gd_midiOutput.h
new file mode 100644 (file)
index 0000000..8dd2fd6
--- /dev/null
@@ -0,0 +1,134 @@
+/* ----------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_midiOutput
+ *
+ * ---------------------------------------------------------------------
+ *
+ * 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 GD_MIDI_OUTPUT_H
+#define GD_MIDI_OUTPUT_H
+
+
+#include <FL/Fl.H>
+#include <stdint.h>
+#include "ge_window.h"
+
+
+/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI
+output master is managed by the configuration window, hence gdMidiOutput deals
+only with channels.
+
+Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set.
+In addition MidiOutputMidiCh has the MIDI message output box. */
+
+/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another
+parent class gdMidiIO to inherit from */
+
+class gdMidiOutput : public gWindow
+{
+protected:
+
+       class gClick *close;
+       class gCheck *enableLightning;
+
+       void stopMidiLearn(class gLearner *l);
+
+       /* cb_learn
+        * callback attached to kernelMidi to learn various actions. */
+
+       static void cb_learn  (uint32_t msg, void *data);
+       inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l);
+
+       /* cb_close
+       close current window. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+       /* cb_enableLightning
+       enable MIDI lightning output. */
+
+       static void cb_enableLightning  (Fl_Widget *w, void *p);
+       inline void __cb_enableLightning();
+
+       /* setTitle
+        * set window title. */
+
+       void setTitle(int chanNum);
+
+public:
+
+       gdMidiOutput(int w, int h);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiOutputMidiCh : public gdMidiOutput
+{
+private:
+
+       static void cb_enableChanList  (Fl_Widget *w, void *p);
+       inline void __cb_enableChanList();
+
+       /* __cb_close
+       override parent method, we need to do more stuff on close. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+       class gCheck  *enableOut;
+       class gChoice *chanListOut;
+
+       class MidiChannel *ch;
+
+public:
+
+       gdMidiOutputMidiCh(class MidiChannel *ch);
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdMidiOutputSampleCh : public gdMidiOutput
+{
+private:
+
+       class SampleChannel *ch;
+
+       /* __cb_close
+       override parent method, we need to do more stuff on close. */
+
+       static void cb_close  (Fl_Widget *w, void *p);
+       inline void __cb_close();
+
+public:
+
+       gdMidiOutputSampleCh(class SampleChannel *ch);
+};
+
+#endif
diff --git a/src/gd_midiOutputSetup.cpp b/src/gd_midiOutputSetup.cpp
deleted file mode 100644 (file)
index 6cc0024..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiOutputSetup
- *
- * ---------------------------------------------------------------------
- *
- * 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 "gd_midiOutputSetup.h"
-#include "ge_mixed.h"
-#include "gg_keyboard.h"
-#include "ge_channel.h"
-#include "channel.h"
-#include "conf.h"
-#include "midiChannel.h"
-#include "gui_utils.h"
-
-
-extern Conf    G_Conf;
-
-
-gdMidiOutputSetup::gdMidiOutputSetup(MidiChannel *ch)
-       : gWindow(300, 64, "Midi Output Setup"), ch(ch)
-{
-       begin();
-       enableOut      = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output");
-       chanListOut    = new gChoice(w()-108, y()+8, 100, 20);
-
-       save   = new gButton(w()-88, chanListOut->y()+chanListOut->h()+8, 80, 20, "Save");
-       cancel = new gButton(w()-88-save->w()-8, save->y(), 80, 20, "Cancel");
-       end();
-
-       fillChanMenu(chanListOut);
-
-       if (ch->midiOut)
-               enableOut->value(1);
-       else
-               chanListOut->deactivate();
-
-       chanListOut->value(ch->midiOutChan);
-
-       enableOut->callback(cb_enableChanList, (void*)this);
-       save->callback(cb_save, (void*)this);
-       cancel->callback(cb_cancel, (void*)this);
-
-       set_modal();
-       gu_setFavicon(this);
-       show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiOutputSetup::cb_save          (Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_save(); }
-void gdMidiOutputSetup::cb_cancel        (Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_cancel(); }
-void gdMidiOutputSetup::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_enableChanList(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiOutputSetup::__cb_enableChanList() {
-       enableOut->value() ? chanListOut->activate() : chanListOut->deactivate();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiOutputSetup::__cb_save() {
-       ch->midiOut     = enableOut->value();
-       ch->midiOutChan = chanListOut->value();
-       ch->guiChannel->update();
-       do_callback();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiOutputSetup::__cb_cancel() { do_callback(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdMidiOutputSetup::fillChanMenu(gChoice *m) {
-       m->add("Channel 1");
-       m->add("Channel 2");
-       m->add("Channel 3");
-       m->add("Channel 4");
-       m->add("Channel 5");
-       m->add("Channel 6");
-       m->add("Channel 7");
-       m->add("Channel 8");
-       m->add("Channel 9");
-       m->add("Channel 10");
-       m->add("Channel 11");
-       m->add("Channel 12");
-       m->add("Channel 13");
-       m->add("Channel 14");
-       m->add("Channel 15");
-       m->add("Channel 16");
-       m->value(0);
-}
diff --git a/src/gd_midiOutputSetup.h b/src/gd_midiOutputSetup.h
deleted file mode 100644 (file)
index 9acf603..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_midiOutputSetup
- *
- * ---------------------------------------------------------------------
- *
- * 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 GD_MIDI_OUTPUT_SETUP_H
-#define GD_MIDI_OUTPUT_SETUP_H
-
-
-#include <FL/Fl.H>
-#include "ge_window.h"
-
-
-class gdMidiOutputSetup : public gWindow {
-
-private:
-
-       static void cb_save          (Fl_Widget *w, void *p);
-       static void cb_cancel        (Fl_Widget *w, void *p);
-       static void cb_enableChanList(Fl_Widget *w, void *p);
-       inline void __cb_save          ();
-       inline void __cb_cancel        ();
-       inline void __cb_enableChanList();
-
-       void fillChanMenu(class gChoice *m);
-
-       class gCheck  *enableOut;
-       class gChoice *chanListOut;
-       class gButton *save;
-       class gButton *cancel;
-
-       class MidiChannel *ch;
-
-public:
-
-       gdMidiOutputSetup(class MidiChannel *ch);
-};
-
-#endif
index d244ad681ab619939990a3bc5910f8a7a3b73965..71cfb384a8380073969acad984fa75696c927fc0 100644 (file)
@@ -1,10 +1,10 @@
-/* -----------------------------------------------------------------------------
+/* ---------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * ge_channel
  *
- * -----------------------------------------------------------------------------
+ * ---------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * -------------------------------------------------------------------------- */
+ * ------------------------------------------------------------------ */
 
 
 #include "ge_channel.h"
 #include "ge_sampleChannel.h"
 #include "gd_mainWindow.h"
 #include "gd_keyGrabber.h"
-#include "gd_midiGrabber.h"
+#include "gd_midiInput.h"
 #include "gd_editor.h"
 #include "gd_actionEditor.h"
 #include "gd_warnings.h"
 #include "gd_browser.h"
-#include "gd_midiOutputSetup.h"
+#include "gd_midiOutput.h"
 #include "gg_keyboard.h"
 #include "pluginHost.h"
 #include "mixer.h"
index d9dfbf4a03f4ba7cbcc4df92c10abac02fa0b873..33cd9913c7525559a83238fd8a623b75bd117399 100644 (file)
 #include "ge_sampleChannel.h"
 #include "gd_mainWindow.h"
 #include "gd_keyGrabber.h"
-#include "gd_midiGrabber.h"
+#include "gd_midiInput.h"
 #include "gd_editor.h"
 #include "gd_actionEditor.h"
 #include "gd_warnings.h"
 #include "gd_browser.h"
 #include "gd_keyGrabber.h"
-#include "gd_midiOutputSetup.h"
+#include "gd_midiOutput.h"
 #include "gg_keyboard.h"
 #include "pluginHost.h"
 #include "mixer.h"
@@ -228,13 +228,14 @@ void gMidiChannel::__cb_openMenu()
                return;
        }
 
-       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiOutputSetup(ch), 0);
+       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
                return;
        }
 
-       if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch), 0);
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0);
+               gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0);
                return;
        }
 }
diff --git a/src/ge_midiIoTools.cpp b/src/ge_midiIoTools.cpp
new file mode 100644 (file)
index 0000000..da9b873
--- /dev/null
@@ -0,0 +1,105 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiIoTools
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 "ge_midiIoTools.h"
+#include "ge_mixed.h"
+
+
+gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param)
+       : Fl_Group(X, Y, W, 20),
+               callback(cb),
+               param   (param)
+{
+       begin();
+       text   = new gBox(x(), y(), 156, 20, l);
+       value  = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)");
+       button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn");
+       end();
+
+       text->box(G_BOX);
+       text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+
+       value->box(G_BOX);
+       value->callback(cb_value, (void*)this);
+       value->when(FL_WHEN_RELEASE);
+       updateValue();
+
+       button->type(FL_TOGGLE_BUTTON);
+       button->callback(cb_button, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::updateValue() {
+       char buf[16];
+       if (*param != 0x0)
+               snprintf(buf, 9, "0x%X", *param);
+       else
+               snprintf(buf, 16, "(not set)");
+       value->copy_label(buf);
+       button->value(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); }
+void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gLearner::__cb_value() {
+       if (Fl::event_button() == FL_RIGHT_MOUSE) {
+               *param = 0x0;
+               updateValue();
+       }
+       /// TODO - elif (LEFT_MOUSE) : insert values by hand
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* FIXME - do not malloc on each callback! do it on the constructor! */
+
+void gLearner::__cb_button() {
+       if (button->value() == 1) {
+               cbData *data  = (cbData*) malloc(sizeof(cbData));
+               data->window  = (gdMidiInput*) parent();  // parent = gdMidiGrabberChannel
+               data->learner = this;
+               kernelMidi::startMidiLearn(callback, (void*)data);
+       }
+       else
+               kernelMidi::stopMidiLearn();
+}
diff --git a/src/ge_midiIoTools.h b/src/ge_midiIoTools.h
new file mode 100644 (file)
index 0000000..bd52756
--- /dev/null
@@ -0,0 +1,92 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * ge_midiIoTools
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 GE_LEARNER_H
+#define GE_LEARNER_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include "gd_midiInput.h"
+#include "kernelMidi.h"
+
+
+class gLearner : public Fl_Group
+{
+private:
+
+       /* callback
+        * cb to pass to kernelMidi. Requires two parameters:
+        * uint32_t msg - MIDI message
+        * void   *data - extra data */
+
+       kernelMidi::cb_midiLearn *callback;
+
+       class gBox    *text;
+       class gClick  *value;
+       class gButton *button;
+
+       static void cb_button(Fl_Widget *v, void *p);
+       static void cb_value (Fl_Widget *v, void *p);
+       inline void __cb_button();
+       inline void __cb_value();
+
+public:
+
+       /* param
+        * pointer to ch->midiIn[value] */
+
+       uint32_t *param;
+
+       gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param);
+
+       void updateValue();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* cbData
+ * struct we pass to kernelMidi as extra parameter. Local scope made
+ * with unnamed namespace. Infos:
+ * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */
+
+/* TODO - instead of the unnamed namespace, why don't we make the struct as a
+(static) member of gLearner? */
+
+namespace {
+       struct cbData {
+               gdMidiInput *window;
+               gLearner    *learner;
+       };
+}
+
+
+#endif
index 11bc005d1aec820d01a411c7a65f68453f979014..7d0f846495b12a23328e796ac5e0c01078ee82f7 100644 (file)
 #include "ge_sampleChannel.h"
 #include "gd_mainWindow.h"
 #include "gd_keyGrabber.h"
-#include "gd_midiGrabber.h"
+#include "gd_midiInput.h"
 #include "gd_editor.h"
 #include "gd_actionEditor.h"
 #include "gd_warnings.h"
 #include "gd_browser.h"
-#include "gd_midiOutputSetup.h"
+#include "gd_midiOutput.h"
 #include "gg_keyboard.h"
 #include "pluginHost.h"
 #include "mixer.h"
@@ -196,23 +196,24 @@ void gSampleChannel::__cb_openMenu()
                {"Export sample to file..."},               // 1
                {"Setup keyboard input..."},                // 2
                {"Setup MIDI input..."},                    // 3
-               {"Edit sample..."},                         // 4
-               {"Edit actions..."},                        // 5
-               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 6
-                       {"All"},                                  // 7
-                       {"Mute"},                                 // 8
-                       {"Volume"},                               // 9
-                       {"Start/Stop"},                           // 10
-                       {0},                                      // 11
-               {"Free channel"},                           // 12
-               {"Delete channel"},                         // 13
+               {"Setup MIDI output..."},                   // 4
+               {"Edit sample..."},                         // 5
+               {"Edit actions..."},                        // 6
+               {"Clear actions", 0, 0, 0, FL_SUBMENU},     // 7
+                       {"All"},                                  // 8
+                       {"Mute"},                                 // 9
+                       {"Volume"},                               // 10
+                       {"Start/Stop"},                           // 11
+                       {0},                                      // 12
+               {"Free channel"},                           // 13
+               {"Delete channel"},                         // 14
                {0}
        };
 
        if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) {
                rclick_menu[1].deactivate();
-               rclick_menu[4].deactivate();
-               rclick_menu[12].deactivate();
+               rclick_menu[5].deactivate();
+               rclick_menu[13].deactivate();
        }
 
        /* no 'clear actions' if there are no actions */
@@ -246,7 +247,12 @@ void gSampleChannel::__cb_openMenu()
        }
 
        if (strcmp(m->label(), "Setup MIDI input...") == 0) {
-               gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch), 0);
+               gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0);
+               return;
+       }
+
+       if (strcmp(m->label(), "Setup MIDI output...") == 0) {
+               gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0);
                return;
        }
 
index 7844175aaa578b4884b6b22e4eab41a0932c0943..60d0a17043aa7b6e84ddd80e6403f3148b052988 100644 (file)
@@ -795,6 +795,7 @@ void glue_setSoloOn(Channel *ch, bool gui)
        }
 
        ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
 
        /* mute all other channels and unmute this (if muted) */
 
@@ -858,6 +859,7 @@ void glue_setSoloOff(Channel *ch, bool gui)
        }
 
        ch->solo = !ch->solo;
+       ch->sendMidiLsolo();
 
        if (!gui) {
                Fl::lock();
index 51915b7cbbafdc60f36e7219bccee002806fae8d..beeab0428c2fc5a25e1a55c95cefee94978ef413 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * init
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include <ctime>
@@ -39,6 +39,7 @@
 #include "conf.h"
 #include "pluginHost.h"
 #include "recorder.h"
+#include "midiMapConf.h"
 #include "gd_mainWindow.h"
 #include "gui_utils.h"
 #include "gd_warnings.h"
@@ -50,6 +51,7 @@ extern bool                              G_audio_status;
 extern bool                               G_quit;
 extern Patch              G_Patch;
 extern Conf          G_Conf;
+extern MidiMapConf   G_MidiMap;
 extern gdMainWindow *mainWin;
 
 #ifdef WITH_VST
@@ -70,7 +72,7 @@ void init_prepareParser()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void init_prepareKernelAudio()
@@ -88,7 +90,7 @@ void init_prepareKernelAudio()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void init_prepareKernelMIDI()
@@ -99,7 +101,18 @@ void init_prepareKernelMIDI()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+
+
+void init_prepareMidiMap()
+{
+       G_MidiMap.init();
+       G_MidiMap.setDefault();
+       G_MidiMap.readMap(G_Conf.midiMapPath);
+}
+
+
+/* -------------------------------------------------------------------------- */
 
 
 void init_startGUI(int argc, char **argv)
@@ -125,7 +138,7 @@ void init_startGUI(int argc, char **argv)
                );
 }
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void init_startKernelAudio()
@@ -139,7 +152,7 @@ void init_startKernelAudio()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void init_shutdown()
index 42a11027d96b8bd743b27637ebb18af4efbcb683..0824f6588b65265a53b28c6d9971e3618f717d58 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * init
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #ifndef INIT_H
@@ -42,6 +42,7 @@ void init_prepareParser();
 void init_startGUI(int argc, char **argv);
 void init_prepareKernelAudio();
 void init_prepareKernelMIDI();
+void init_prepareMidiMap();
 void init_startKernelAudio();
 void init_shutdown();
 
index 3a424241d2607c8919b035673c88defa4c3029a5..1d4f99b3c810015539e4a5382cde5eb679be8f6e 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * KernelMidi
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include <stdio.h>
 #include "sampleChannel.h"
 #include "pluginHost.h"
 #include "conf.h"
+#include "midiMapConf.h"
 #include "log.h"
 
 
-extern bool  G_midiStatus;
-extern Conf  G_Conf;
-extern Mixer G_Mixer;
+extern bool        G_midiStatus;
+extern Conf        G_Conf;
+extern Mixer       G_Mixer;
+extern MidiMapConf G_MidiMap;
 
 #ifdef WITH_VST
-extern PluginHost G_PluginHost;
+extern PluginHost  G_PluginHost;
 #endif
 
 
@@ -60,7 +62,7 @@ cb_midiLearn *cb_learn = NULL;
 void         *cb_data  = NULL;
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void startMidiLearn(cb_midiLearn *cb, void *data)
@@ -70,7 +72,7 @@ void startMidiLearn(cb_midiLearn *cb, void *data)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void stopMidiLearn()
@@ -80,7 +82,7 @@ void stopMidiLearn()
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void setApi(int _api)
@@ -90,7 +92,7 @@ void setApi(int _api)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int openOutDevice(int port)
@@ -118,6 +120,19 @@ int openOutDevice(int port)
                try {
                        midiOut->openPort(port, getOutPortName(port));
                        gLog("[KM] MIDI out port %d open\n", port);
+
+                       /* for each init command of MidiMap, send the init commands to the
+                       external world. TODO 1 - we shold do that only if there is a map loaded
+                       and available in MidiMap.
+                       TODO 2 - move the map initialization to another function */
+
+                       for(int i=0; i<G_MidiMap.MAX_INIT_COMMANDS; i++) {
+                               if (G_MidiMap.init_messages[i] != 0x0 && G_MidiMap.init_channels[i] != -1) {
+                                       gLog("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", G_MidiMap.init_channels[i], G_MidiMap.init_messages[i]);
+                                       send(G_MidiMap.init_messages[i] | MIDI_CHANS[G_MidiMap.init_channels[i]]);
+                               }
+                       }
+
                        return 1;
                }
                catch (RtMidiError &error) {
@@ -131,7 +146,7 @@ int openOutDevice(int port)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 int openInDevice(int port)
@@ -174,7 +189,7 @@ int openInDevice(int port)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 bool hasAPI(int API)
@@ -188,7 +203,7 @@ bool hasAPI(int API)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 const char *getOutPortName(unsigned p)
@@ -204,7 +219,7 @@ const char *getInPortName(unsigned p)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void send(uint32_t data)
@@ -212,21 +227,16 @@ void send(uint32_t data)
        if (!G_midiStatus)
                return;
 
-       //std::vector<unsigned char> msg(1, 0x00);
-       //msg[0] = getB1(data);
-       //msg[1] = getB2(data);
-       //msg[2] = getB3(data);
-
   std::vector<unsigned char> msg(1, getB1(data));
   msg.push_back(getB2(data));
   msg.push_back(getB3(data));
 
        midiOut->sendMessage(&msg);
-       //gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
+       gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void send(int b1, int b2, int b3)
@@ -246,7 +256,7 @@ void send(int b1, int b2, int b3)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void callback(double t, std::vector<unsigned char> *msg, void *data)
@@ -255,7 +265,7 @@ void callback(double t, std::vector<unsigned char> *msg, void *data)
         * messages) as unknown, for debugging purposes */
 
        if (msg->size() < 3) {
-               gLog("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
+               gLog("[KM] MIDI received - unkown signal - size=%d, value=0x", (int) msg->size());
                for (unsigned i=0; i<msg->size(); i++)
                        gLog("%X", (int) msg->at(i));
                gLog("\n");
@@ -373,7 +383,7 @@ void callback(double t, std::vector<unsigned char> *msg, void *data)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 std::string getRtMidiVersion()
index b17bbeb31a19124de67adec07cc7f1f08e9a6488..d44699510f4c2443a7d749c8a9be964170823b92 100644 (file)
@@ -97,7 +97,7 @@ namespace kernelMidi {
         * master callback for input events. */
 
        void callback(double t, std::vector<unsigned char> *msg, void *data);
-       
+
        std::string getRtMidiVersion();
 }
 
index 687fb055a65a00c15de5b3b412f2b9d00cdfcdeb..e714162a88701544d7f83d6847b673e77d9605f0 100644 (file)
@@ -33,6 +33,7 @@
 #include "const.h"
 #include "patch.h"
 #include "conf.h"
+#include "midiMapConf.h"
 #include "mixer.h"
 #include "mixerHandler.h"
 #include "kernelAudio.h"
@@ -53,6 +54,7 @@ bool          G_audio_status;
 bool          G_midiStatus;
 Patch        G_Patch;
 Conf                 G_Conf;
+MidiMapConf       G_MidiMap;
 gdMainWindow *mainWin;
 
 #ifdef WITH_VST
@@ -68,6 +70,7 @@ int main(int argc, char **argv) {
        G_quit = false;
 
        init_prepareParser();
+       init_prepareMidiMap();
        init_prepareKernelAudio();
        init_prepareKernelMIDI();
        init_startGUI(argc, argv);
index f1e43b7e92425061f794a59352579dc0018761e8..6f386840b6d4ddb2120f3ec97cdf8d5a6bb95111 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * channel
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include "channel.h"
@@ -55,18 +55,19 @@ MidiChannel::MidiChannel(int bufferSize)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 MidiChannel::~MidiChannel() {}
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 #ifdef WITH_VST
 
-void MidiChannel::freeVstMidiEvents(bool init) {
+void MidiChannel::freeVstMidiEvents(bool init)
+{
        if (events.numEvents == 0 && !init)
                return;
        memset(events.events, 0, sizeof(VstEvent*) * MAX_VST_EVENTS);
@@ -77,30 +78,32 @@ void MidiChannel::freeVstMidiEvents(bool init) {
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 #ifdef WITH_VST
 
-void MidiChannel::addVstMidiEvent(uint32_t msg) {
+void MidiChannel::addVstMidiEvent(uint32_t msg)
+{
        addVstMidiEvent(G_PluginHost.createVstMidiEvent(msg));
 }
 
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 #ifdef WITH_VST
 
-void MidiChannel::addVstMidiEvent(VstMidiEvent *e) {
-       if (events.numEvents < MAX_VST_EVENTS) {        
+void MidiChannel::addVstMidiEvent(VstMidiEvent *e)
+{
+       if (events.numEvents < MAX_VST_EVENTS) {
                events.events[events.numEvents] = (VstEvent*) e;
                events.numEvents++;
                /*
-               gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n", 
-                       events.numEvents, 
+               gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n",
+                       events.numEvents,
                        e->deltaFrames,
                        e->midiData[0],
                        e->midiData[1],
@@ -114,87 +117,99 @@ void MidiChannel::addVstMidiEvent(VstMidiEvent *e) {
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void MidiChannel::onBar(int frame) {}
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void MidiChannel::stop() {}
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void MidiChannel::empty() {}
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void MidiChannel::quantize(int index, int localFrame, int globalFrame) {}
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 #ifdef WITH_VST
 
-VstEvents *MidiChannel::getVstEvents() {
+VstEvents *MidiChannel::getVstEvents()
+{
        return (VstEvents *) &events;
 }
 
 #endif
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) {
+void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
+{
        if (a->type == ACTION_MIDI)
                sendMidi(a, localFrame/2);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::onZero(int frame) {
-       if (status == STATUS_ENDING)
+void MidiChannel::onZero(int frame)
+{
+       if (status == STATUS_ENDING) {
                status = STATUS_OFF;
+               sendMidiLplay();
+       }
        else
-       if (status == STATUS_WAIT)
+       if (status == STATUS_WAIT) {
                status = STATUS_PLAY;
+               sendMidiLplay();
+       }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::setMute(bool internal) {
+void MidiChannel::setMute(bool internal)
+{
        mute = true;    // internal mute does not exist for midi (for now)
        if (midiOut)
                kernelMidi::send(MIDI_ALL_NOTES_OFF);
 #ifdef WITH_VST
                addVstMidiEvent(MIDI_ALL_NOTES_OFF);
 #endif
+       sendMidiLmute();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::unsetMute(bool internal) {
+void MidiChannel::unsetMute(bool internal)
+{
        mute = false;   // internal mute does not exist for midi (for now)
+       sendMidiLmute();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::process(float *buffer) {
+void MidiChannel::process(float *buffer)
+{
 #ifdef WITH_VST
        G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
        freeVstMidiEvents();
@@ -207,37 +222,43 @@ void MidiChannel::process(float *buffer) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::start(int frame, bool doQuantize) {
+void MidiChannel::start(int frame, bool doQuantize)
+{
        switch (status) {
                case STATUS_PLAY:
                        status = STATUS_ENDING;
+                       sendMidiLplay();
                        break;
                case STATUS_ENDING:
                case STATUS_WAIT:
                        status = STATUS_OFF;
+                       sendMidiLplay();
                        break;
                case STATUS_OFF:
                        status = STATUS_WAIT;
+                       sendMidiLplay();
                        break;
        }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::stopBySeq() {
+void MidiChannel::stopBySeq()
+{
        kill(0);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::kill(int frame) {
+void MidiChannel::kill(int frame)
+{
        if (status & (STATUS_PLAY | STATUS_ENDING)) {
                if (midiOut)
                        kernelMidi::send(MIDI_ALL_NOTES_OFF);
@@ -246,13 +267,15 @@ void MidiChannel::kill(int frame) {
 #endif
        }
        status = STATUS_OFF;
+       sendMidiLplay();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int MidiChannel::loadByPatch(const char *f, int i) {
+int MidiChannel::loadByPatch(const char *f, int i)
+{
        volume      = G_Patch.getVol(i);
        index       = G_Patch.getIndex(i);
        mute        = G_Patch.getMute(i);
@@ -265,15 +288,16 @@ int MidiChannel::loadByPatch(const char *f, int i) {
        midiOutChan = G_Patch.getMidiValue(i, "OutChan");
 
        readPatchMidiIn(i);
+       readPatchMidiOut(i);
 
        return SAMPLE_LOADED_OK;  /// TODO - change name, it's meaningless here
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::sendMidi(recorder::action *a, int localFrame) 
+void MidiChannel::sendMidi(recorder::action *a, int localFrame)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
                if (midiOut)
@@ -287,7 +311,7 @@ void MidiChannel::sendMidi(recorder::action *a, int localFrame)
 }
 
 
-void MidiChannel::sendMidi(uint32_t data) 
+void MidiChannel::sendMidi(uint32_t data)
 {
        if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
                if (midiOut)
@@ -299,10 +323,11 @@ void MidiChannel::sendMidi(uint32_t data)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::rewind() {
+void MidiChannel::rewind()
+{
        if (midiOut)
                kernelMidi::send(MIDI_ALL_NOTES_OFF);
 #ifdef WITH_VST
@@ -311,7 +336,7 @@ void MidiChannel::rewind() {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 void MidiChannel::writePatch(FILE *fp, int i, bool isProject)
diff --git a/src/midiMapConf.cpp b/src/midiMapConf.cpp
new file mode 100644 (file)
index 0000000..7fa8268
--- /dev/null
@@ -0,0 +1,223 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * midiMapConf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <iostream>
+#include <string>
+#include <sstream>
+#include <dirent.h>
+#include "midiMapConf.h"
+#include "const.h"
+#include "utils.h"
+#include "log.h"
+
+
+using std::string;
+
+
+void MidiMapConf::init()
+{
+       midimapsPath = gGetHomePath() + "/midimaps/";
+
+       /* scan dir of midi maps and load the filenames into <>maps. */
+
+       gLog("[MidiMapConf::init] scanning midimaps directory...\n");
+
+  DIR    *dp;
+  dirent *ep;
+  dp = opendir(midimapsPath.c_str());
+
+       if (!dp) {
+               gLog("[MidiMapConf::init] unable to scan midimaps directory!\n");
+               return;
+       }
+
+       while ((ep = readdir(dp))) {
+               if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+                       continue;
+
+               // TODO - check if is a valid midimap file (verify headers)
+
+               gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name);
+
+               maps.add(ep->d_name);
+       }
+
+       closedir(dp);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::setDefault()
+{
+       brand  = "";
+       device = "";
+
+       for (int i=0; i<MAX_INIT_COMMANDS; i++) {
+               init_channels[i] = -1;
+               init_messages[i] = 0x00;
+       }
+
+       muteOnChan     = 0;
+       muteOnOffset   = 0;
+       muteOnMsg      = 0;
+
+       muteOffChan    = 0;
+       muteOffOffset  = 0;
+       muteOffMsg     = 0;
+
+       soloOnChan     = 0;
+       soloOnOffset   = 0;
+       soloOnMsg      = 0;
+
+       soloOffChan    = 0;
+       soloOffOffset  = 0;
+       soloOffMsg     = 0;
+
+       waitingChan    = 0;
+       waitingOffset  = 0;
+       waitingMsg     = 0;
+
+       playingChan    = 0;
+       playingOffset  = 0;
+       playingMsg     = 0;
+
+       stoppingChan   = 0;
+       stoppingOffset = 0;
+       stoppingMsg    = 0;
+
+       stoppedChan    = 0;
+       stoppedOffset  = 0;
+       stoppedMsg     = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int MidiMapConf::readMap(string file)
+{
+       if (file.empty()) {
+               gLog("[MidiMapConf::readFromFile] midimap not specified, nothing to do\n");
+               return 0;
+       }
+
+       gLog("[MidiMapConf::readFromFile] reading midimap file '%s'\n", file.c_str());
+
+       string path = midimapsPath + file;
+       fp = fopen(path.c_str(), "r");
+       if (!fp) {
+               gLog("[MidiMapConf::readFromFile] unreadable midimap file\n");
+               return 0;
+       }
+
+       brand  = getValue("brand");
+       device = getValue("device");
+
+       gLog("[MidiMapConf::readFromFile] reading midimap for %s %s\n",
+                       brand.c_str(), device.c_str());
+
+       /* parse init commands */
+
+       gVector<string> ic;
+       gSplit(getValue("init_commands"), ";", &ic);
+       for (unsigned i=0; i<MAX_INIT_COMMANDS && i<ic.size; i++) {
+               sscanf(ic.at(i).c_str(), "%d:%x", &init_channels[i], &init_messages[i]);
+               gLog("[MidiMapConf::readFromFile] init command %d - channel %d - message 0x%X\n",
+                               i, init_channels[i], init_messages[i]);
+       }
+
+       /* parse messages */
+
+       parse("mute_on",  &muteOnChan,   &muteOnMsg,   &muteOnOffset);
+       parse("mute_off", &muteOffChan,  &muteOffMsg,  &muteOffOffset);
+       parse("solo_on",  &soloOnChan,   &soloOnMsg,   &soloOnOffset);
+       parse("solo_off", &soloOffChan,  &soloOffMsg,  &soloOffOffset);
+       parse("waiting",  &waitingChan,  &waitingMsg,  &waitingOffset);
+       parse("playing",  &playingChan,  &playingMsg,  &playingOffset);
+       parse("stopping", &stoppingChan, &stoppingMsg, &stoppingOffset);
+       parse("stopped",  &stoppedChan,  &stoppedMsg,  &stoppedOffset);
+
+       close();
+       return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::close()
+{
+       if (fp != NULL)
+               fclose(fp);
+       fp = NULL;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiMapConf::parse(string key, int *chan, uint32_t *msg, int *offset)
+{
+       gLog("[MidiMapConf::parse2] command %s - ", key.c_str());
+       string value = getValue(key.c_str());
+
+       /* grab channel part, i.e. [channel]:*/
+
+       *chan = atoi(value.substr(0, value.find(':')).c_str());
+
+       /* grab MIDI part :[midi-message] and search for 'nn' note placeholder within.
+        * Note: when using 'string::npos' as the value for a len (or sublen)
+        * parameter in string's member functions, means "until the end of the
+        * string". */
+
+       string midiParts = value.substr(value.find(':')+3, string::npos);
+
+       char strmsg[MAX_MIDI_NIBBLES];
+       *offset = 0;
+
+       /* build the message as a string, for each char (i.e. nibble) in the
+        * original string. Substitute 'n' with zeros. */
+
+       for (unsigned i=0, p=24; i<MAX_MIDI_NIBBLES; i++, p-=4) {
+               if (midiParts[i] == 'n') {
+                       strmsg[i] = '0';
+                       if (*offset == 0)
+                               *offset = p;
+               }
+               else
+                       strmsg[i] = midiParts[i];
+       }
+
+       *msg = strtoul(strmsg, NULL, 16);  // from string to uint32_t
+
+       gLog("chan=%d value=%s msg=%#x, offset=%d\n", *chan, midiParts.c_str(), *msg, *offset);
+}
diff --git a/src/midiMapConf.h b/src/midiMapConf.h
new file mode 100644 (file)
index 0000000..3ff65fa
--- /dev/null
@@ -0,0 +1,133 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * midiMapConf
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 __MIDIMAPCONF_H__
+#define __MIDIMAPCONF_H__
+
+
+#include <limits.h>
+#include <stdint.h>
+#include "dataStorage.h"
+#include "utils.h"
+#if defined(__APPLE__)
+#include <pwd.h>
+#endif
+
+
+using std::string;
+
+
+class MidiMapConf : public DataStorage
+{
+private:
+
+       void close();
+       void parse(string key, int *chan, uint32_t *msg, int *offset);
+
+public:
+
+       static const int MAX_INIT_COMMANDS = 32;
+       static const int MAX_MIDI_BYTES = 4;
+       static const int MAX_MIDI_NIBBLES = 8;
+
+       /* midimapsPath
+        * path of midimap files, different between OSes. */
+
+       string midimapsPath;
+
+       /* maps
+        * Maps are the available .giadamap files. Each element of the vector
+        * represents a .giadamap filename. */
+
+       gVector<string> maps;
+
+       string brand;
+       string device;
+
+       /* init_*
+        * init_commands. These messages are sent to the physical device as a wake up
+        * signal. */
+
+       int      init_channels[MAX_INIT_COMMANDS];
+       uint32_t init_messages[MAX_INIT_COMMANDS];
+
+       /* events
+        * [event]Channel: the MIDI output channel to send the event to
+        * [event]notePos: the byte where the note is stored ('nn' placeholder)
+        * [event]offset:  the note offset (i.e. of 'nn' placeholder) */
+
+       int      muteOnChan;
+       int      muteOnOffset;
+       uint32_t muteOnMsg;
+
+       int      muteOffChan;
+       int      muteOffOffset;
+       uint32_t muteOffMsg;
+
+       int      soloOnChan;
+       int      soloOnOffset;
+       uint32_t soloOnMsg;
+
+       int      soloOffChan;
+       int      soloOffOffset;
+       uint32_t soloOffMsg;
+
+       int      waitingChan;
+       int      waitingOffset;
+       uint32_t waitingMsg;
+
+       int      playingChan;
+       int      playingOffset;
+       uint32_t playingMsg;
+
+       int      stoppingChan;
+       int      stoppingOffset;
+       uint32_t stoppingMsg;
+
+       int      stoppedChan;
+       int      stoppedOffset;
+       uint32_t stoppedMsg;
+
+       /* init
+       Parse the midi maps folders and find the available maps. */
+
+       void init();
+
+       /* setDefault
+       Set default values in case no maps are available/choosen. */
+
+       void setDefault();
+
+       /* readMap
+       Read a midi map from file 'file'. */
+
+       int readMap(string file);
+};
+
+#endif
index 300db28c24b3430d32f7c31d592fa1a5fa713144..1b9cb29ae1c5a0c2e2e708f8ccf9a669baaaa3b0 100644 (file)
@@ -1,10 +1,10 @@
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * channel
  *
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
  *
  * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
  *
@@ -24,7 +24,7 @@
  * along with Giada - Your Hardcore Loopmachine. If not, see
  * <http://www.gnu.org/licenses/>.
  *
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
 
 
 #include <math.h>
@@ -35,6 +35,7 @@
 #include "pluginHost.h"
 #include "waveFx.h"
 #include "mixerHandler.h"
+#include "kernelMidi.h"
 #include "log.h"
 
 
@@ -72,10 +73,11 @@ SampleChannel::SampleChannel(int bufferSize)
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-SampleChannel::~SampleChannel() {
+SampleChannel::~SampleChannel()
+{
        if (wave)
                delete wave;
        src_delete(rsmp_state);
@@ -83,11 +85,11 @@ SampleChannel::~SampleChannel() {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::clear() {
 
+void SampleChannel::clear()
+{
        /** TODO - these memsets can be done only if status PLAY (if below),
         * but it would require extra clearPChan calls when samples stop */
 
@@ -104,11 +106,11 @@ void SampleChannel::clear() {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::calcVolumeEnv(int frame) {
 
+void SampleChannel::calcVolumeEnv(int frame)
+{
        /* method: check this frame && next frame, then calculate delta */
 
        recorder::action *a0 = NULL;
@@ -137,21 +139,24 @@ void SampleChannel::calcVolumeEnv(int frame) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::hardStop(int frame) {
+void SampleChannel::hardStop(int frame)
+{
        if (frame != 0)        // clear data in range [frame, bufferSize-1]
                clearChan(vChan, frame);
        status = STATUS_OFF;
+       sendMidiLplay();
        reset(frame);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::onBar(int frame) {
+void SampleChannel::onBar(int frame)
+{
        ///if (mode == LOOP_REPEAT && status == STATUS_PLAY)
        ///     //setXFade(frame);
        ///     reset(frame);
@@ -166,41 +171,45 @@ void SampleChannel::onBar(int frame) {
                if (status == STATUS_WAIT) {
                        status  = STATUS_PLAY;
                        tracker = fillChan(vChan, tracker, frame);
+                       sendMidiLplay();
                }
        }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::save(const char *path) {
+int SampleChannel::save(const char *path)
+{
        return wave->writeData(path);
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setBegin(unsigned v) {
+void SampleChannel::setBegin(unsigned v)
+{
        begin   = v;
        tracker = begin;
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setEnd(unsigned v) {
+void SampleChannel::setEnd(unsigned v)
+{
        end = v;
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setPitch(float v) {
-
+void SampleChannel::setPitch(float v)
+{
        pitch = v;
        rsmp_data.src_ratio = 1/pitch;
 
@@ -211,11 +220,11 @@ void SampleChannel::setPitch(float v) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::rewind() {
-
+void SampleChannel::rewind()
+{
        /* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */
 
        if (wave != NULL) {
@@ -225,11 +234,11 @@ void SampleChannel::rewind() {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) {
 
+void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
+{
        if (readActions == false)
                return;
 
@@ -259,11 +268,11 @@ void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalF
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::sum(int frame, bool running) {
 
+void SampleChannel::sum(int frame, bool running)
+{
        if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING))
                return;
 
@@ -349,14 +358,17 @@ void SampleChannel::sum(int frame, bool running) {
                         (mode & LOOP_ANY && !running))     // stop loops when the seq is off
                {
                        status = STATUS_OFF;
+                       sendMidiLplay();
                }
 
                /* temporary stop LOOP_ONCE not in ENDING status, otherwise they
                 * would return in wait, losing the ENDING status */
 
                //if (mode == LOOP_ONCE && status != STATUS_ENDING)
-               if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING)
+               if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING) {
                        status = STATUS_WAIT;
+                       sendMidiLplay();
+               }
 
                /* check for end of samples. SINGLE_ENDLESS runs forever unless
                 * it's in ENDING mode. */
@@ -366,11 +378,11 @@ void SampleChannel::sum(int frame, bool running) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::onZero(int frame) {
-
+void SampleChannel::onZero(int frame)
+{
        if (wave == NULL)
                return;
 
@@ -395,6 +407,7 @@ void SampleChannel::onZero(int frame) {
 
        if (status == STATUS_WAIT) { /// FIXME - should be inside previous if!
                status  = STATUS_PLAY;
+               sendMidiLplay();
                tracker = fillChan(vChan, tracker, frame);
        }
 
@@ -410,11 +423,11 @@ void SampleChannel::onZero(int frame) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::quantize(int index, int localFrame, int globalFrame) {
-
+void SampleChannel::quantize(int index, int localFrame, int globalFrame)
+{
        /* skip if LOOP_ANY or not in quantizer-wait mode */
 
        if ((mode & LOOP_ANY) || !qWait)
@@ -425,6 +438,7 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) {
 
        if (status == STATUS_OFF) {
                status  = STATUS_PLAY;
+               sendMidiLplay();
                qWait   = false;
                tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ???
        }
@@ -444,10 +458,11 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::getPosition() {
+int SampleChannel::getPosition()
+{
        if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...)
                return tracker - begin;
        else
@@ -455,11 +470,11 @@ int SampleChannel::getPosition() {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::setMute(bool internal) {
 
+void SampleChannel::setMute(bool internal)
+{
        if (internal) {
 
                /* global mute is on? don't waste time with fadeout, just mute it
@@ -491,13 +506,16 @@ void SampleChannel::setMute(bool internal) {
                                mute = true;
                }
        }
+
+       sendMidiLmute();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::unsetMute(bool internal) {
+void SampleChannel::unsetMute(bool internal)
+{
        if (internal) {
                if (mute)
                        mute_i = false;
@@ -518,13 +536,16 @@ void SampleChannel::unsetMute(bool internal) {
                                mute = false;
                }
        }
+
+       sendMidiLmute();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::calcFadeoutStep() {
+void SampleChannel::calcFadeoutStep()
+{
        if (end - tracker < (1 / DEFAULT_FADEOUT_STEP) * 2)
                fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ???
        else
@@ -532,10 +553,11 @@ void SampleChannel::calcFadeoutStep() {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setReadActions(bool v) {
+void SampleChannel::setReadActions(bool v)
+{
        if (v)
                readActions = true;
        else {
@@ -546,10 +568,11 @@ void SampleChannel::setReadActions(bool v) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setFadeIn(bool internal) {
+void SampleChannel::setFadeIn(bool internal)
+{
        if (internal) mute_i = false;  // remove mute before fading in
        else          mute   = false;
        fadeinOn  = true;
@@ -557,10 +580,11 @@ void SampleChannel::setFadeIn(bool internal) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::setFadeOut(int actionPostFadeout) {
+void SampleChannel::setFadeOut(int actionPostFadeout)
+{
        calcFadeoutStep();
        fadeoutOn   = true;
        fadeoutVol  = 1.0f;
@@ -569,11 +593,11 @@ void SampleChannel::setFadeOut(int actionPostFadeout) {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::setXFade(int frame) {
 
+void SampleChannel::setXFade(int frame)
+{
        gLog("[xFade] frame=%d tracker=%d\n", frame, tracker);
 
        calcFadeoutStep();
@@ -585,7 +609,7 @@ void SampleChannel::setXFade(int frame) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
 /* on reset, if frame > 0 and in play, fill again pChan to create
@@ -596,7 +620,8 @@ void SampleChannel::setXFade(int frame) {
  *
  * */
 
-void SampleChannel::reset(int frame) {
+void SampleChannel::reset(int frame)
+{
        //fadeoutTracker = tracker;   // store old frame number for xfade
        tracker = begin;
        mute_i  = false;
@@ -605,35 +630,39 @@ void SampleChannel::reset(int frame) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::empty() {
+void SampleChannel::empty()
+{
        status = STATUS_OFF;
        if (wave) {
                delete wave;
                wave = NULL;
        }
        status = STATUS_EMPTY;
+       sendMidiLplay();
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::pushWave(Wave *w) {
+void SampleChannel::pushWave(Wave *w)
+{
        wave   = w;
        status = STATUS_OFF;
+       sendMidiLplay();
        begin  = 0;
        end    = wave->size;
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-bool SampleChannel::allocEmpty(int frames, int takeId) {
-
+bool SampleChannel::allocEmpty(int frames, int takeId)
+{
        Wave *w = new Wave();
        if (!w->allocEmpty(frames))
                return false;
@@ -648,15 +677,17 @@ bool SampleChannel::allocEmpty(int frames, int takeId) {
        begin       = 0;
        end         = wave->size;
 
+       sendMidiLplay();
+
        return true;
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::process(float *buffer) {
 
+void SampleChannel::process(float *buffer)
+{
 #ifdef WITH_VST
        G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this);
 #endif
@@ -668,10 +699,11 @@ void SampleChannel::process(float *buffer) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::kill(int frame) {
+void SampleChannel::kill(int frame)
+{
        if (wave != NULL && status != STATUS_OFF) {
                if (mute || mute_i || (status == STATUS_WAIT && mode & LOOP_ANY))
                        hardStop(frame);
@@ -681,11 +713,11 @@ void SampleChannel::kill(int frame) {
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::stopBySeq() {
 
+void SampleChannel::stopBySeq()
+{
        /* kill loop channels and recs if "samplesStopOnSeqHalt" == true,
         * else do nothing and return. Always kill at frame=0, this is a
         * user-generated event. */
@@ -710,10 +742,11 @@ void SampleChannel::stopBySeq() {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::stop() {
+void SampleChannel::stop()
+{
        if (mode == SINGLE_PRESS && status == STATUS_PLAY) {
                if (mute || mute_i)
                        hardStop(0);  /// FIXME - wrong frame value
@@ -726,11 +759,11 @@ void SampleChannel::stop() {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::load(const char *file) {
-
+int SampleChannel::load(const char *file)
+{
        if (strcmp(file, "") == 0 || gIsDir(file)) {
                gLog("[SampleChannel] file not specified\n");
                return SAMPLE_LEFT_EMPTY;
@@ -783,11 +816,11 @@ int SampleChannel::load(const char *file) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::loadByPatch(const char *f, int i) {
-
+int SampleChannel::loadByPatch(const char *f, int i)
+{
        int res = load(f);
 
                volume      = G_Patch.getVol(i);
@@ -806,6 +839,7 @@ int SampleChannel::loadByPatch(const char *f, int i) {
                readPatchMidiIn(i);
                midiInReadActions = G_Patch.getMidiValue(i, "InReadActions");
                midiInPitch       = G_Patch.getMidiValue(i, "InPitch");
+               readPatchMidiOut(i);
 
        if (res == SAMPLE_LOADED_OK) {
                setBegin(G_Patch.getBegin(i));
@@ -823,25 +857,27 @@ int SampleChannel::loadByPatch(const char *f, int i) {
                else
                if (res == SAMPLE_READ_ERROR)
                        status = STATUS_MISSING;
+               sendMidiLplay();
        }
 
        return res;
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-bool SampleChannel::canInputRec() {
+bool SampleChannel::canInputRec()
+       {
        return wave == NULL;
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-void SampleChannel::start(int frame, bool doQuantize) {
 
+void SampleChannel::start(int frame, bool doQuantize)
+{
        switch (status) {
                case STATUS_EMPTY:
                case STATUS_MISSING:
@@ -854,6 +890,7 @@ void SampleChannel::start(int frame, bool doQuantize) {
                {
                        if (mode & LOOP_ANY) {
                                status = STATUS_WAIT;
+                               sendMidiLplay();
                        }
                        else {
                                if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
@@ -864,6 +901,7 @@ void SampleChannel::start(int frame, bool doQuantize) {
                                         * a duplicate call to fillChan occurs with loss of data. */
 
                                        status = STATUS_PLAY;
+                                       sendMidiLplay();
                                        if (frame != 0)
                                                tracker = fillChan(vChan, tracker, frame);
                                }
@@ -883,31 +921,35 @@ void SampleChannel::start(int frame, bool doQuantize) {
                                        reset(frame);
                        }
                        else
-                       if (mode & (LOOP_ANY | SINGLE_ENDLESS))
+                       if (mode & (LOOP_ANY | SINGLE_ENDLESS)) {
                                status = STATUS_ENDING;
+                               sendMidiLplay();
+                       }
                        break;
                }
 
                case STATUS_WAIT:
                {
                        status = STATUS_OFF;
+                       sendMidiLplay();
                        break;
                }
 
                case STATUS_ENDING:
                {
                        status = STATUS_PLAY;
+                       sendMidiLplay();
                        break;
                }
        }
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::writePatch(FILE *fp, int i, bool isProject) {
-
+void SampleChannel::writePatch(FILE *fp, int i, bool isProject)
+{
        Channel::writePatch(fp, i, isProject);
 
        const char *path = "";
@@ -932,19 +974,20 @@ void SampleChannel::writePatch(FILE *fp, int i, bool isProject) {
 }
 
 
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::clearChan(float *dest, int start) {
+void SampleChannel::clearChan(float *dest, int start)
+{
        memset(dest+start, 0, sizeof(float)*(bufferSize-start));
 }
 
 
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
 
-int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind) {
 
+int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind)
+{
        int position;  // return value: the new position
 
        if (pitch == 1.0f) {