+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
# 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
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
#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
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)
/* -------------------------------------------------------------------------- */
+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");
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");
+}
+
/* -------------------------------------------------------------------------- */
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);
+ }
}
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);
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;
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
* 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();
};
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* conf
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* 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>
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;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
int Conf::createConfigFolder(const char *path)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
int Conf::openFileForWriting()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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;
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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());
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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);
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void Conf::close()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void Conf::setPath(char *path, const char *p)
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* conf
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#ifndef __CONF_H__
int midiPortOut;
int midiPortIn;
bool noNoteOff;
+ char midiMapPath[FILENAME_MAX];
+ char lastFileMap[FILENAME_MAX];
int midiSync; // see const.h
float midiTCfps;
/* -- 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"
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* 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"
}
return out;
}
-
-
-
-
-
FILE *fp;
std::string getValue(const char *in);
-
};
#endif
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
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* 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)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabMisc::save()
}
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
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(); }
void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_showOutputInfo(); }
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::__cb_fetchInChans()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::__cb_fetchOutChans()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::__cb_showInputInfo()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::__cb_showOutputInfo()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::__cb_deactivate_sounddev()
}
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::fetchInChans(int menuItem)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::fetchOutChans(int menuItem)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
int gTabAudio::findMenuDevice(gChoice *m, int device)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::fetchSoundDevs()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabAudio::save()
}
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
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();
fetchSystems();
fetchOutPorts();
fetchInPorts();
+ fetchMidiMaps();
noNoteOff->value(G_Conf.noNoteOff);
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabMidi::fetchOutPorts() {
}
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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()
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;
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)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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__)
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()
}
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
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)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gTabBehaviors::save()
}
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration")
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void gdConfig::__cb_cancel()
#include "ge_window.h"
-class gdConfig : public gWindow
+class gdConfig : public gWindow
{
private:
static void cb_save_config (Fl_Widget *w, void *p);
/* ------------------------------------------------------------------ */
-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();
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);
/* ------------------------------------------------------------------ */
-class gTabAudio : public Fl_Group
+class gTabAudio : public Fl_Group
{
private:
static void cb_deactivate_sounddev(Fl_Widget *w, void *p);
/* ------------------------------------------------------------------ */
-class gTabBehaviors : public Fl_Group
+class gTabBehaviors : public Fl_Group
{
private:
static void cb_radio_mutex (Fl_Widget *w, void *p);
/* ------------------------------------------------------------------ */
-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);
#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"
return;
}
if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
- gu_openSubWindow(mainWin, new gdMidiGrabberMaster(), 0);
+ gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0);
return;
}
}
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * 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();
-}
-
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * 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
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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();
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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();
+}
--- /dev/null
+/* ----------------------------------------------------------------------
+ *
+ * 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
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * 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);
-}
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * 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
-/* -----------------------------------------------------------------------------
+/* ---------------------------------------------------------------------
*
* 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"
#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"
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;
}
}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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();
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
#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"
{"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 */
}
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;
}
}
ch->solo = !ch->solo;
+ ch->sendMidiLsolo();
/* mute all other channels and unmute this (if muted) */
}
ch->solo = !ch->solo;
+ ch->sendMidiLsolo();
if (!gui) {
Fl::lock();
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* init
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#include <ctime>
#include "conf.h"
#include "pluginHost.h"
#include "recorder.h"
+#include "midiMapConf.h"
#include "gd_mainWindow.h"
#include "gui_utils.h"
#include "gd_warnings.h"
extern bool G_quit;
extern Patch G_Patch;
extern Conf G_Conf;
+extern MidiMapConf G_MidiMap;
extern gdMainWindow *mainWin;
#ifdef WITH_VST
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void init_prepareKernelAudio()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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)
);
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void init_startKernelAudio()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void init_shutdown()
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* init
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#ifndef INIT_H
void init_startGUI(int argc, char **argv);
void init_prepareKernelAudio();
void init_prepareKernelMIDI();
+void init_prepareMidiMap();
void init_startKernelAudio();
void init_shutdown();
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* KernelMidi
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* 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
void *cb_data = NULL;
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void startMidiLearn(cb_midiLearn *cb, void *data)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void stopMidiLearn()
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void setApi(int _api)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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) {
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
int openInDevice(int port)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
bool hasAPI(int API)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
const char *getOutPortName(unsigned p)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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");
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
std::string getRtMidiVersion()
* master callback for input events. */
void callback(double t, std::vector<unsigned char> *msg, void *data);
-
+
std::string getRtMidiVersion();
}
#include "const.h"
#include "patch.h"
#include "conf.h"
+#include "midiMapConf.h"
#include "mixer.h"
#include "mixerHandler.h"
#include "kernelAudio.h"
bool G_midiStatus;
Patch G_Patch;
Conf G_Conf;
+MidiMapConf G_MidiMap;
gdMainWindow *mainWin;
#ifdef WITH_VST
G_quit = false;
init_prepareParser();
+ init_prepareMidiMap();
init_prepareKernelAudio();
init_prepareKernelMIDI();
init_startGUI(argc, argv);
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* channel
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#include "channel.h"
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
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);
#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],
#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();
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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);
#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);
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)
}
-void MidiChannel::sendMidi(uint32_t data)
+void MidiChannel::sendMidi(uint32_t data)
{
if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) {
if (midiOut)
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void MidiChannel::rewind() {
+void MidiChannel::rewind()
+{
if (midiOut)
kernelMidi::send(MIDI_ALL_NOTES_OFF);
#ifdef WITH_VST
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
void MidiChannel::writePatch(FILE *fp, int i, bool isProject)
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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);
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * 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
-/* ---------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
*
* Giada - Your Hardcore Loopmachine
*
* channel
*
- * ---------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual
*
* along with Giada - Your Hardcore Loopmachine. If not, see
* <http://www.gnu.org/licenses/>.
*
- * ------------------------------------------------------------------ */
+ * -------------------------------------------------------------------------- */
#include <math.h>
#include "pluginHost.h"
#include "waveFx.h"
#include "mixerHandler.h"
+#include "kernelMidi.h"
#include "log.h"
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-SampleChannel::~SampleChannel() {
+SampleChannel::~SampleChannel()
+{
if (wave)
delete wave;
src_delete(rsmp_state);
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-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 */
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-void SampleChannel::calcVolumeEnv(int frame) {
+void SampleChannel::calcVolumeEnv(int frame)
+{
/* method: check this frame && next frame, then calculate delta */
recorder::action *a0 = NULL;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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);
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;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::rewind() {
-
+void SampleChannel::rewind()
+{
/* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */
if (wave != NULL) {
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) {
+void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame)
+{
if (readActions == false)
return;
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-void SampleChannel::sum(int frame, bool running) {
+void SampleChannel::sum(int frame, bool running)
+{
if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING))
return;
(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. */
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::onZero(int frame) {
-
+void SampleChannel::onZero(int frame)
+{
if (wave == NULL)
return;
if (status == STATUS_WAIT) { /// FIXME - should be inside previous if!
status = STATUS_PLAY;
+ sendMidiLplay();
tracker = fillChan(vChan, tracker, 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)
if (status == STATUS_OFF) {
status = STATUS_PLAY;
+ sendMidiLplay();
qWait = false;
tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ???
}
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-int SampleChannel::getPosition() {
+int SampleChannel::getPosition()
+{
if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...)
return tracker - begin;
else
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-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
mute = true;
}
}
+
+ sendMidiLmute();
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::unsetMute(bool internal) {
+void SampleChannel::unsetMute(bool internal)
+{
if (internal) {
if (mute)
mute_i = false;
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
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::setReadActions(bool v) {
+void SampleChannel::setReadActions(bool v)
+{
if (v)
readActions = true;
else {
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::setFadeOut(int actionPostFadeout) {
+void SampleChannel::setFadeOut(int actionPostFadeout)
+{
calcFadeoutStep();
fadeoutOn = true;
fadeoutVol = 1.0f;
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-void SampleChannel::setXFade(int frame) {
+void SampleChannel::setXFade(int frame)
+{
gLog("[xFade] frame=%d tracker=%d\n", frame, tracker);
calcFadeoutStep();
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
/* on reset, if frame > 0 and in play, fill again pChan to create
*
* */
-void SampleChannel::reset(int frame) {
+void SampleChannel::reset(int frame)
+{
//fadeoutTracker = tracker; // store old frame number for xfade
tracker = begin;
mute_i = false;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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;
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
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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);
}
-/* ------------------------------------------------------------------ */
-
+/* -------------------------------------------------------------------------- */
-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. */
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-void SampleChannel::stop() {
+void SampleChannel::stop()
+{
if (mode == SINGLE_PRESS && status == STATUS_PLAY) {
if (mute || mute_i)
hardStop(0); /// FIXME - wrong frame value
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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;
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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);
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));
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:
{
if (mode & LOOP_ANY) {
status = STATUS_WAIT;
+ sendMidiLplay();
}
else {
if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize)
* a duplicate call to fillChan occurs with loss of data. */
status = STATUS_PLAY;
+ sendMidiLplay();
if (frame != 0)
tracker = fillChan(vChan, tracker, frame);
}
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 = "";
}
-/* ------------------------------------------------------------------ */
+/* -------------------------------------------------------------------------- */
-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) {