From: Jaromír Mikeš Date: Tue, 7 Jul 2015 12:42:31 +0000 (+0200) Subject: Imported Upstream version 0.10.0~dfsg1 X-Git-Tag: archive/raspbian/0.15.4+ds1-1+rpi1^2~12^2~21 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=02f23ec68556cc8931df796955875f44ab332184;p=giada.git Imported Upstream version 0.10.0~dfsg1 --- diff --git a/ChangeLog b/ChangeLog index 712ae50..b662cd6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,11 @@ +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 diff --git a/configure.ac b/configure.ac index 6ddcf0b..5bb3b59 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ # prereq & init AC_PREREQ(2.60) -AC_INIT([giada], [0.9], [giadaloopmachine@gmail.com]) +AC_INIT([giada], [0.10], [giadaloopmachine@gmail.com]) AC_CONFIG_SRCDIR([src/main.cpp]) AM_INIT_AUTOMAKE diff --git a/src/Makefile.am b/src/Makefile.am index 644c35d..a717df4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,11 +37,12 @@ gd_actionEditor.h gd_actionEditor.cpp ge_muteChannel.h ge_muteChannel. ge_actionChannel.h ge_actionChannel.cpp gd_pluginWindowGUI.h gd_pluginWindowGUI.cpp \ ge_actionWidget.h ge_actionWidget.cpp ge_envelopeChannel.h ge_envelopeChannel.cpp \ ge_pianoRoll.h ge_pianoRoll.cpp kernelMidi.h kernelMidi.cpp \ -gd_midiOutputSetup.h gd_midiOutputSetup.cpp gd_midiGrabber.h gd_midiGrabber.cpp \ +gd_midiOutput.h gd_midiOutput.cpp gd_midiInput.h gd_midiInput.cpp \ sampleChannel.h sampleChannel.cpp midiChannel.cpp midiChannel.h \ -ge_channel.h ge_channel.cpp log.h log.cpp \ -ge_column.h ge_column.cpp ge_sampleChannel.h ge_sampleChannel.cpp \ -ge_midiChannel.h ge_midiChannel.cpp +midiMapConf.cpp midiMapConf.h ge_channel.h ge_channel.cpp \ +log.h log.cpp ge_column.h ge_column.cpp \ +ge_sampleChannel.h ge_sampleChannel.cpp ge_midiChannel.h ge_midiChannel.cpp \ +ge_midiIoTools.h ge_midiIoTools.cpp diff --git a/src/channel.cpp b/src/channel.cpp index f9a3b7c..6c4c48e 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -28,7 +28,6 @@ #include "channel.h" -#include "ge_channel.h" #include "pluginHost.h" #include "kernelMidi.h" #include "patch.h" @@ -38,11 +37,14 @@ #include "conf.h" #include "waveFx.h" #include "log.h" +#include "midiMapConf.h" +#include "ge_channel.h" extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; +extern MidiMapConf G_MidiMap; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif @@ -66,13 +68,17 @@ Channel::Channel(int type, int status, int bufferSize) recStatus (REC_STOPPED), vChan (NULL), guiChannel(NULL), - midiIn (true), - midiInKeyPress(0x0), - midiInKeyRel (0x0), - midiInKill (0x0), - midiInVolume (0x0), - midiInMute (0x0), - midiInSolo (0x0) + midiIn (true), + midiInKeyPress (0x0), + midiInKeyRel (0x0), + midiInKill (0x0), + midiInVolume (0x0), + midiInMute (0x0), + midiInSolo (0x0), + midiOutL (false), + midiOutLplaying(0x0), + midiOutLmute (0x0), + midiOutLsolo (0x0) { vChan = (float *) malloc(bufferSize * sizeof(float)); if (!vChan) @@ -95,6 +101,29 @@ Channel::~Channel() /* -------------------------------------------------------------------------- */ +void Channel::sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset) +{ + gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n", + learn, chan, msg, offset); + + uint32_t out; + + /* isolate 'channel' from learnt message and offset it as requested by 'nn' + * in the midimap configuration file. */ + + out = ((learn & 0x00FF0000) >> 16) << offset; + + /* merge the previously prepared channel into final message, and finally + * send it. */ + + out |= msg | (chan << 24); + kernelMidi::send(out); +} + + +/* -------------------------------------------------------------------------- */ + + void Channel::readPatchMidiIn(int i) { midiIn = G_Patch.getMidiValue(i, "In"); @@ -106,6 +135,14 @@ void Channel::readPatchMidiIn(int i) midiInSolo = G_Patch.getMidiValue(i, "InSolo"); } +void Channel::readPatchMidiOut(int i) +{ + midiOutL = G_Patch.getMidiValue(i, "OutL"); + midiOutLplaying = G_Patch.getMidiValue(i, "OutLplaying"); + midiOutLmute = G_Patch.getMidiValue(i, "OutLmute"); + midiOutLsolo = G_Patch.getMidiValue(i, "OutLsolo"); +} + /* -------------------------------------------------------------------------- */ @@ -138,4 +175,60 @@ void Channel::writePatch(FILE *fp, int i, bool isProject) fprintf(fp, "chanMidiInVolume%d=%u\n", i, midiInVolume); fprintf(fp, "chanMidiInMute%d=%u\n", i, midiInMute); fprintf(fp, "chanMidiInSolo%d=%u\n", i, midiInSolo); + + fprintf(fp, "chanMidiOutL%d=%u\n", i, midiOutL); + fprintf(fp, "chanMidiOutLplaying%d=%u\n", i, midiOutLplaying); + fprintf(fp, "chanMidiOutLmute%d=%u\n", i, midiOutLmute); + fprintf(fp, "chanMidiOutLsolo%d=%u\n", i, midiOutLsolo); +} + + +/* -------------------------------------------------------------------------- */ + + +void Channel::sendMidiLmute() +{ + if (!midiOutL || midiOutLmute == 0x0) + return; + if (mute) + sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOnChan, G_MidiMap.muteOnMsg, G_MidiMap.muteOnOffset); + else + sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOffChan, G_MidiMap.muteOffMsg, G_MidiMap.muteOffOffset); +} + + +/* -------------------------------------------------------------------------- */ + + +void Channel::sendMidiLsolo() +{ + if (!midiOutL || midiOutLsolo == 0x0) + return; + if (solo) + sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOnChan, G_MidiMap.soloOnMsg, G_MidiMap.soloOnOffset); + else + sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOffChan, G_MidiMap.soloOffMsg, G_MidiMap.soloOffOffset); +} + + +/* -------------------------------------------------------------------------- */ + + +void Channel::sendMidiLplay() +{ + if (!midiOutL || midiOutLplaying == 0x0) + return; + switch (status) { + case STATUS_OFF: + sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppedChan, G_MidiMap.stoppedMsg, G_MidiMap.stoppedOffset); + break; + case STATUS_PLAY: + sendMidiLmessage(midiOutLplaying, G_MidiMap.playingChan, G_MidiMap.playingMsg, G_MidiMap.playingOffset); + break; + case STATUS_WAIT: + sendMidiLmessage(midiOutLplaying, G_MidiMap.waitingChan, G_MidiMap.waitingMsg, G_MidiMap.waitingOffset); + break; + case STATUS_ENDING: + sendMidiLmessage(midiOutLplaying, G_MidiMap.stoppingChan, G_MidiMap.stoppingMsg, G_MidiMap.stoppingOffset); + } } diff --git a/src/channel.h b/src/channel.h index 6540fab..fa34eac 100644 --- a/src/channel.h +++ b/src/channel.h @@ -61,6 +61,12 @@ protected: int bufferSize; + /* sendMidiLMessage + * compose a MIDI message by merging bytes from MidiMap conf class, and send + * it to KernelMidi. */ + + void sendMidiLmessage(uint32_t learn, int chan, uint32_t msg, int offset); + public: Channel(int type, int status, int bufferSize); @@ -164,7 +170,9 @@ public: float *vChan; // virtual channel class gChannel *guiChannel; // pointer to a gChannel object, part of the GUI - bool midiIn; // enable midi output + // TODO - midi structs, please + + bool midiIn; // enable midi input uint32_t midiInKeyPress; uint32_t midiInKeyRel; uint32_t midiInKill; @@ -172,6 +180,16 @@ public: uint32_t midiInMute; uint32_t midiInSolo; + /* midiOutL* + * Enable MIDI lightning output, plus a set of midi lighting event to be sent + * to a device. Those events basically contains the MIDI channel, everything + * else gets stripped out. */ + + bool midiOutL; + uint32_t midiOutLplaying; + uint32_t midiOutLmute; + uint32_t midiOutLsolo; + #ifdef WITH_VST gVector plugins; #endif @@ -189,6 +207,14 @@ public: * and so on. */ void readPatchMidiIn(int i); + void readPatchMidiOut(int i); + + /* sendMidiL* + * send MIDI lightning events to a physical device. */ + + void sendMidiLmute(); + void sendMidiLsolo(); + void sendMidiLplay(); }; diff --git a/src/conf.cpp b/src/conf.cpp index af1a4fe..fd6720e 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * conf * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -36,25 +36,8 @@ int Conf::openFileForReading() { - char path[PATH_MAX]; - -#if defined(__linux__) - snprintf(path, PATH_MAX, "%s/.giada/%s", getenv("HOME"), CONF_FILENAME); -#elif defined(_WIN32) - snprintf(path, PATH_MAX, "%s", CONF_FILENAME); -#elif defined(__APPLE__) - struct passwd *p = getpwuid(getuid()); - if (p == NULL) { - gLog("[Conf::openFile] unable to fetch user infos\n"); - return 0; - } - else { - const char *home = p->pw_dir; - snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada/giada.conf", home); - } -#endif - - fp = fopen(path, "r"); + std::string path = gGetHomePath() + "/" + CONF_FILENAME; + fp = fopen(path.c_str(), "r"); if (fp == NULL) { gLog("[Conf::openFile] unable to open conf file for reading\n"); return 0; @@ -63,7 +46,7 @@ int Conf::openFileForReading() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int Conf::createConfigFolder(const char *path) @@ -84,7 +67,7 @@ int Conf::createConfigFolder(const char *path) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int Conf::openFileForWriting() @@ -130,7 +113,7 @@ int Conf::openFileForWriting() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void Conf::setDefault() @@ -146,11 +129,12 @@ void Conf::setDefault() limitOutput = false; rsmpQuality = 0; - midiPortIn = DEFAULT_MIDI_PORT_IN; - noNoteOff = false; - midiPortOut = DEFAULT_MIDI_PORT_OUT; - midiSync = MIDI_SYNC_NONE; - midiTCfps = 25.0f; + midiPortIn = DEFAULT_MIDI_PORT_IN; + noNoteOff = false; + midiMapPath[0] = '\0'; + midiPortOut = DEFAULT_MIDI_PORT_OUT; + midiSync = MIDI_SYNC_NONE; + midiTCfps = 25.0f; midiInRewind = 0x0; midiInStartStop = 0x0; @@ -187,7 +171,7 @@ void Conf::setDefault() -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int Conf::read() @@ -237,6 +221,14 @@ int Conf::read() noNoteOff = atoi(getValue("noNoteOff").c_str()); + std::string tmpMidiMapPath = getValue("midiMapPath"); + strncpy(midiMapPath, tmpMidiMapPath.c_str(), tmpMidiMapPath.size()); + midiMapPath[tmpMidiMapPath.size()] = '\0'; // strncpy doesn't add '\0' + + std::string tmplastFileMap = getValue("lastFileMap"); + strncpy(lastFileMap, tmplastFileMap.c_str(), tmplastFileMap.size()); + lastFileMap[tmplastFileMap.size()] = '\0'; // strncpy doesn't add '\0' + midiSync = atoi(getValue("midiSync").c_str()); midiTCfps = atof(getValue("midiTCfps").c_str()); @@ -351,7 +343,7 @@ int Conf::read() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int Conf::write() @@ -380,6 +372,8 @@ int Conf::write() fprintf(fp, "midiPortOut=%d\n", midiPortOut); fprintf(fp, "midiPortIn=%d\n", midiPortIn); fprintf(fp, "noNoteOff=%d\n", noNoteOff); + fprintf(fp, "midiMapPath=%s\n", midiMapPath); + fprintf(fp, "lastFileMap=%s\n", lastFileMap); fprintf(fp, "midiSync=%d\n", midiSync); fprintf(fp, "midiTCfps=%f\n", midiTCfps); @@ -452,7 +446,7 @@ int Conf::write() -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void Conf::close() @@ -462,7 +456,7 @@ void Conf::close() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void Conf::setPath(char *path, const char *p) diff --git a/src/conf.h b/src/conf.h index 69ea870..9120f2e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * conf * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef __CONF_H__ @@ -68,6 +68,8 @@ public: int midiPortOut; int midiPortIn; bool noNoteOff; + char midiMapPath[FILENAME_MAX]; + char lastFileMap[FILENAME_MAX]; int midiSync; // see const.h float midiTCfps; diff --git a/src/const.h b/src/const.h index a0b5152..9ada42e 100644 --- a/src/const.h +++ b/src/const.h @@ -31,9 +31,9 @@ /* -- version --------------------------------------------------------------- */ -#define VERSIONE "0.9.6" +#define VERSIONE "0.10.0" #define VERSIONE_STR "Giada" -#define VERSIONE_FLOAT 0.96f +#define VERSIONE_FLOAT 1.0f #define CONF_FILENAME "giada.conf" diff --git a/src/dataStorage.cpp b/src/dataStorage.cpp index 4704afc..43729e8 100644 --- a/src/dataStorage.cpp +++ b/src/dataStorage.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * dataStorage * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,10 +24,13 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ +#include +#include #include "dataStorage.h" +#include "const.h" #include "log.h" @@ -65,8 +68,3 @@ std::string DataStorage::getValue(const char *in) { } return out; } - - - - - diff --git a/src/dataStorage.h b/src/dataStorage.h index 4232b68..9d54ddf 100644 --- a/src/dataStorage.h +++ b/src/dataStorage.h @@ -43,7 +43,6 @@ protected: FILE *fp; std::string getValue(const char *in); - }; #endif diff --git a/src/gd_browser.h b/src/gd_browser.h index b5e8734..61f482d 100644 --- a/src/gd_browser.h +++ b/src/gd_browser.h @@ -90,9 +90,13 @@ private: int stackType; + char selectedFile[FILENAME_MAX]; + public: gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0); ~gdBrowser(); + + char* SelectedFile(); }; #endif diff --git a/src/gd_config.cpp b/src/gd_config.cpp index 54f2627..ab34fc6 100644 --- a/src/gd_config.cpp +++ b/src/gd_config.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_config * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,14 +24,16 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #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" @@ -42,9 +44,10 @@ extern Patch G_Patch; extern Conf G_Conf; extern bool G_audio_status; +extern MidiMapConf G_MidiMap; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gTabMisc::gTabMisc(int X, int Y, int W, int H) @@ -74,7 +77,7 @@ gTabMisc::gTabMisc(int X, int Y, int W, int H) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMisc::save() @@ -93,9 +96,9 @@ void gTabMisc::save() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gTabAudio::gTabAudio(int X, int Y, int W, int H) @@ -216,7 +219,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_deactivate_sounddev(); } @@ -226,7 +229,7 @@ void gTabAudio::cb_showInputInfo(Fl_Widget *w, void *p) { ((gTabAudio*)p)- void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_showOutputInfo(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::__cb_fetchInChans() @@ -236,7 +239,7 @@ void gTabAudio::__cb_fetchInChans() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::__cb_fetchOutChans() @@ -246,7 +249,7 @@ void gTabAudio::__cb_fetchOutChans() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::__cb_showInputInfo() @@ -256,7 +259,7 @@ void gTabAudio::__cb_showInputInfo() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::__cb_showOutputInfo() @@ -266,7 +269,7 @@ void gTabAudio::__cb_showOutputInfo() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::__cb_deactivate_sounddev() @@ -309,7 +312,7 @@ void gTabAudio::__cb_deactivate_sounddev() } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::fetchInChans(int menuItem) @@ -346,7 +349,7 @@ void gTabAudio::fetchInChans(int menuItem) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::fetchOutChans(int menuItem) @@ -370,7 +373,7 @@ void gTabAudio::fetchOutChans(int menuItem) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int gTabAudio::findMenuDevice(gChoice *m, int device) @@ -394,7 +397,7 @@ int gTabAudio::findMenuDevice(gChoice *m, int device) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::fetchSoundDevs() @@ -462,7 +465,7 @@ void gTabAudio::fetchSoundDevs() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabAudio::save() @@ -512,9 +515,9 @@ void gTabAudio::save() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gTabMidi::gTabMidi(int X, int Y, int W, int H) @@ -525,7 +528,8 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H) portOut = new gChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port"); portIn = new gChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port"); noNoteOff = new gCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff"); - sync = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Sync"); + midiMap = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map"); + sync = new gChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync"); new gBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect."); end(); @@ -536,6 +540,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H) fetchSystems(); fetchOutPorts(); fetchInPorts(); + fetchMidiMaps(); noNoteOff->value(G_Conf.noNoteOff); @@ -553,7 +558,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMidi::fetchOutPorts() { @@ -579,7 +584,7 @@ void gTabMidi::fetchOutPorts() { } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMidi::fetchInPorts() @@ -606,7 +611,27 @@ void gTabMidi::fetchInPorts() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ + + +void gTabMidi::fetchMidiMaps() +{ + if (G_MidiMap.maps.size == 0) { + midiMap->add("(no MIDI maps available)"); + midiMap->value(0); + midiMap->deactivate(); + return; + } + for (unsigned i=0; iadd(imap); + if (strcmp(G_Conf.midiMapPath, imap) == 0) + midiMap->value(i); + } +} + + +/* -------------------------------------------------------------------------- */ void gTabMidi::save() @@ -617,8 +642,6 @@ void gTabMidi::save() G_Conf.midiSystem = RtMidi::UNIX_JACK; else if (!strcmp("Multimedia MIDI", system->text(system->value()))) G_Conf.midiSystem = RtMidi::WINDOWS_MM; - //else if (!strcmp("Kernel Streaming MIDI", system->text(system->value()))) - // G_Conf.midiSystem = RtMidi::WINDOWS_KS; else if (!strcmp("OSX Core MIDI", system->text(system->value()))) G_Conf.midiSystem = RtMidi::MACOSX_CORE; @@ -627,6 +650,8 @@ void gTabMidi::save() G_Conf.noNoteOff = noNoteOff->value(); + G_Conf.setPath(G_Conf.midiMapPath, midiMap->text(midiMap->value())); + if (sync->value() == 0) G_Conf.midiSync = MIDI_SYNC_NONE; else if (sync->value() == 1) @@ -636,7 +661,7 @@ void gTabMidi::save() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMidi::fetchSystems() @@ -652,8 +677,6 @@ void gTabMidi::fetchSystems() if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM)) system->add("Multimedia MIDI"); - //if (kernelMidi::hasAPI(RtMidi::WINDOWS_KS)) - // system->add("Kernel Streaming MIDI"); #elif defined (__APPLE__) @@ -665,20 +688,19 @@ void gTabMidi::fetchSystems() case RtMidi::LINUX_ALSA: system->show("ALSA"); break; case RtMidi::UNIX_JACK: system->show("Jack"); break; case RtMidi::WINDOWS_MM: system->show("Multimedia MIDI"); break; - //case RtMidi::WINDOWS_KS: system->show("Kernel Streaming MIDI"); break; case RtMidi::MACOSX_CORE: system->show("OSX Core MIDI"); break; default: system->value(0); break; } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((gTabMidi*)p)->__cb_changeSystem(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabMidi::__cb_changeSystem() @@ -702,9 +724,9 @@ void gTabMidi::__cb_changeSystem() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H) @@ -739,13 +761,13 @@ gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabBehaviors::cb_radio_mutex(Fl_Widget *w, void *p) { ((gTabBehaviors*)p)->__cb_radio_mutex(w); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w) @@ -754,7 +776,7 @@ void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTabBehaviors::save() @@ -765,9 +787,9 @@ void gTabBehaviors::save() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration") @@ -802,7 +824,7 @@ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration") } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gdConfig::~gdConfig() @@ -812,14 +834,14 @@ gdConfig::~gdConfig() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdConfig::cb_save_config(Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_save_config(); } void gdConfig::cb_cancel (Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_cancel(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdConfig::__cb_save_config() @@ -832,7 +854,7 @@ void gdConfig::__cb_save_config() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdConfig::__cb_cancel() diff --git a/src/gd_config.h b/src/gd_config.h index 1cfc202..fa28b80 100644 --- a/src/gd_config.h +++ b/src/gd_config.h @@ -35,7 +35,7 @@ #include "ge_window.h" -class gdConfig : public gWindow +class gdConfig : public gWindow { private: static void cb_save_config (Fl_Widget *w, void *p); @@ -59,12 +59,14 @@ public: /* ------------------------------------------------------------------ */ -class gTabMidi : public Fl_Group +class gTabMidi : public Fl_Group { private: + void fetchSystems(); void fetchOutPorts(); void fetchInPorts(); + void fetchMidiMaps(); static void cb_changeSystem (Fl_Widget *w, void *p); inline void __cb_changeSystem(); @@ -72,10 +74,12 @@ private: int systemInitValue; public: + class gChoice *system; class gChoice *portOut; class gChoice *portIn; class gCheck *noNoteOff; + class gChoice *midiMap; class gChoice *sync; gTabMidi(int x, int y, int w, int h); @@ -87,7 +91,7 @@ public: /* ------------------------------------------------------------------ */ -class gTabAudio : public Fl_Group +class gTabAudio : public Fl_Group { private: static void cb_deactivate_sounddev(Fl_Widget *w, void *p); @@ -131,7 +135,7 @@ public: /* ------------------------------------------------------------------ */ -class gTabBehaviors : public Fl_Group +class gTabBehaviors : public Fl_Group { private: static void cb_radio_mutex (Fl_Widget *w, void *p); @@ -153,10 +157,10 @@ public: /* ------------------------------------------------------------------ */ -class gTabMisc : public Fl_Group +class gTabMisc : public Fl_Group { public: - class gChoice *debugMsg; + class gChoice *debugMsg; gTabMisc(int x, int y, int w, int h); diff --git a/src/gd_mainWindow.cpp b/src/gd_mainWindow.cpp index 45ebccb..b8fc2df 100644 --- a/src/gd_mainWindow.cpp +++ b/src/gd_mainWindow.cpp @@ -35,7 +35,7 @@ #include "gd_warnings.h" #include "gd_bpmInput.h" #include "gd_beatsInput.h" -#include "gd_midiGrabber.h" +#include "gd_midiInput.h" #include "gg_keyboard.h" #include "gd_about.h" #include "gd_config.h" @@ -413,7 +413,7 @@ void gMenu::__cb_edit() return; } if (strcmp(m->label(), "Setup global MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiGrabberMaster(), 0); + gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0); return; } } diff --git a/src/gd_midiGrabber.cpp b/src/gd_midiGrabber.cpp deleted file mode 100644 index 18a9c3c..0000000 --- a/src/gd_midiGrabber.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiGrabber - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#include "gd_midiGrabber.h" -#include "ge_mixed.h" -#include "gui_utils.h" -#include "kernelMidi.h" -#include "conf.h" -#include "sampleChannel.h" -#include "log.h" - - -extern Conf G_Conf; - - -gdMidiGrabber::gdMidiGrabber(int w, int h, const char *title) - : gWindow(w, h, title) -{ -} - - -/* ------------------------------------------------------------------ */ - - -gdMidiGrabber::~gdMidiGrabber() { - kernelMidi::stopMidiLearn(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabber::stopMidiLearn(gLearner *learner) { - kernelMidi::stopMidiLearn(); - learner->updateValue(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabber::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { - *param = msg; - stopMidiLearn(l); - gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabber::cb_learn(uint32_t msg, void *d) { - cbData *data = (cbData*) d; - gdMidiGrabber *grabber = (gdMidiGrabber*) data->grabber; - gLearner *learner = data->learner; - uint32_t *param = learner->param; - grabber->__cb_learn(param, msg, learner); - free(data); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabber::cb_close(Fl_Widget *w, void *p) { ((gdMidiGrabber*)p)->__cb_close(); } - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabber::__cb_close() { - do_callback(); -} - - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -gdMidiGrabberChannel::gdMidiGrabberChannel(Channel *ch) - : gdMidiGrabber(300, 206, "MIDI Input Setup"), - ch(ch) -{ - char title[64]; - sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1); - label(title); - - set_modal(); - - enable = new gCheck(8, 8, 120, 20, "enable MIDI input"); - new gLearner(8, 30, w()-16, "key press", cb_learn, &ch->midiInKeyPress); - new gLearner(8, 54, w()-16, "key release", cb_learn, &ch->midiInKeyRel); - new gLearner(8, 78, w()-16, "key kill", cb_learn, &ch->midiInKill); - new gLearner(8, 102, w()-16, "mute", cb_learn, &ch->midiInMute); - new gLearner(8, 126, w()-16, "solo", cb_learn, &ch->midiInSolo); - new gLearner(8, 150, w()-16, "volume", cb_learn, &ch->midiInVolume); - int yy = 178; - - if (ch->type == CHANNEL_SAMPLE) { - size(300, 254); - new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); - new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); - yy = 226; - } - - ok = new gButton(w()-88, yy, 80, 20, "Ok"); - ok->callback(cb_close, (void*)this); - - enable->value(ch->midiIn); - enable->callback(cb_enable, (void*)this); - - gu_setFavicon(this); - show(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabberChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiGrabberChannel*)p)->__cb_enable(); } - - -/* ------------------------------------------------------------------ */ - - -void gdMidiGrabberChannel::__cb_enable() { - ch->midiIn = enable->value(); -} - - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -gdMidiGrabberMaster::gdMidiGrabberMaster() - : gdMidiGrabber(300, 256, "MIDI Input Setup (global)") -{ - set_modal(); - - new gLearner(8, 8, w()-16, "rewind", &cb_learn, &G_Conf.midiInRewind); - new gLearner(8, 32, w()-16, "play/stop", &cb_learn, &G_Conf.midiInStartStop); - new gLearner(8, 56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec); - new gLearner(8, 80, w()-16, "input recording", &cb_learn, &G_Conf.midiInInputRec); - new gLearner(8, 104, w()-16, "metronome", &cb_learn, &G_Conf.midiInMetronome); - new gLearner(8, 128, w()-16, "input volume", &cb_learn, &G_Conf.midiInVolumeIn); - new gLearner(8, 152, w()-16, "output volume", &cb_learn, &G_Conf.midiInVolumeOut); - new gLearner(8, 176, w()-16, "sequencer ×2", &cb_learn, &G_Conf.midiInBeatDouble); - new gLearner(8, 200, w()-16, "sequencer ÷2", &cb_learn, &G_Conf.midiInBeatHalf); - ok = new gButton(w()-88, 228, 80, 20, "Ok"); - - ok->callback(cb_close, (void*)this); - - gu_setFavicon(this); - show(); -} - - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param) - : Fl_Group(X, Y, W, 20), - callback(cb), - param (param) -{ - begin(); - text = new gBox(x(), y(), 156, 20, l); - value = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)"); - button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn"); - end(); - - text->box(G_BOX); - text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); - - value->box(G_BOX); - value->callback(cb_value, (void*)this); - value->when(FL_WHEN_RELEASE); - updateValue(); - - button->type(FL_TOGGLE_BUTTON); - button->callback(cb_button, (void*)this); -} - - -/* ------------------------------------------------------------------ */ - - -void gLearner::updateValue() { - char buf[16]; - if (*param != 0x0) - snprintf(buf, 9, "0x%X", *param); - else - snprintf(buf, 16, "(not set)"); - value->copy_label(buf); - button->value(0); -} - - -/* ------------------------------------------------------------------ */ - - -void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); } -void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); } - - -/* ------------------------------------------------------------------ */ - - -void gLearner::__cb_value() { - if (Fl::event_button() == FL_RIGHT_MOUSE) { - *param = 0x0; - updateValue(); - } - /// TODO - elif (LEFT_MOUSE) : insert values by hand -} - - -/* ------------------------------------------------------------------ */ - - -void gLearner::__cb_button() { - if (button->value() == 1) { - cbData *data = (cbData*) malloc(sizeof(cbData)); - data->grabber = (gdMidiGrabber*) parent(); // parent = gdMidiGrabberChannel - data->learner = this; - kernelMidi::startMidiLearn(callback, (void*)data); - } - else - kernelMidi::stopMidiLearn(); -} - diff --git a/src/gd_midiGrabber.h b/src/gd_midiGrabber.h deleted file mode 100644 index 4da9e72..0000000 --- a/src/gd_midiGrabber.h +++ /dev/null @@ -1,150 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiGrabber - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#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 items; for future use, with vst parameters - - static void cb_enable (Fl_Widget *w, void *p); - inline void __cb_enable(); - -public: - - gdMidiGrabberChannel(class Channel *ch); -}; - - -/* ------------------------------------------------------------------ */ - - -class gdMidiGrabberMaster : public gdMidiGrabber { - -public: - - gdMidiGrabberMaster(); -}; - - -/* ------------------------------------------------------------------ */ - - -/* cbData - * struct we pass to kernelMidi as extra parameter. Local scope made - * with unnamed namespace. Infos: - * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */ - -namespace { - struct cbData { - gdMidiGrabber *grabber; - gLearner *learner; - }; -} - - -#endif diff --git a/src/gd_midiInput.cpp b/src/gd_midiInput.cpp new file mode 100644 index 0000000..5d41ae1 --- /dev/null +++ b/src/gd_midiInput.cpp @@ -0,0 +1,184 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiInput + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "gd_midiInput.h" +#include "ge_mixed.h" +#include "ge_midiIoTools.h" +#include "gui_utils.h" +#include "kernelMidi.h" +#include "conf.h" +#include "sampleChannel.h" +#include "log.h" + + +extern Conf G_Conf; + + +gdMidiInput::gdMidiInput(int w, int h, const char *title) + : gWindow(w, h, title) +{ +} + + +/* -------------------------------------------------------------------------- */ + + +gdMidiInput::~gdMidiInput() { + kernelMidi::stopMidiLearn(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInput::stopMidiLearn(gLearner *learner) { + kernelMidi::stopMidiLearn(); + learner->updateValue(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { + *param = msg; + stopMidiLearn(l); + gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInput::cb_learn(uint32_t msg, void *d) { + cbData *data = (cbData*) d; + gdMidiInput *window = (gdMidiInput*) data->window; + gLearner *learner = data->learner; + uint32_t *param = learner->param; + window->__cb_learn(param, msg, learner); + free(data); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInput::cb_close(Fl_Widget *w, void *p) { ((gdMidiInput*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInput::__cb_close() { + do_callback(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +gdMidiInputChannel::gdMidiInputChannel(Channel *ch) + : gdMidiInput(300, 206, "MIDI Input Setup"), + ch(ch) +{ + char title[64]; + sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1); + label(title); + + set_modal(); + + enable = new gCheck(8, 8, 120, 20, "enable MIDI input"); + new gLearner(8, 30, w()-16, "key press", cb_learn, &ch->midiInKeyPress); + new gLearner(8, 54, w()-16, "key release", cb_learn, &ch->midiInKeyRel); + new gLearner(8, 78, w()-16, "key kill", cb_learn, &ch->midiInKill); + new gLearner(8, 102, w()-16, "mute", cb_learn, &ch->midiInMute); + new gLearner(8, 126, w()-16, "solo", cb_learn, &ch->midiInSolo); + new gLearner(8, 150, w()-16, "volume", cb_learn, &ch->midiInVolume); + int yy = 178; + + if (ch->type == CHANNEL_SAMPLE) { + size(300, 254); + new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); + new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); + yy = 226; + } + + ok = new gButton(w()-88, yy, 80, 20, "Close"); + ok->callback(cb_close, (void*)this); + + enable->value(ch->midiIn); + enable->callback(cb_enable, (void*)this); + + gu_setFavicon(this); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiInputChannel*)p)->__cb_enable(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiInputChannel::__cb_enable() { + ch->midiIn = enable->value(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +gdMidiInputMaster::gdMidiInputMaster() + : gdMidiInput(300, 256, "MIDI Input Setup (global)") +{ + set_modal(); + + new gLearner(8, 8, w()-16, "rewind", &cb_learn, &G_Conf.midiInRewind); + new gLearner(8, 32, w()-16, "play/stop", &cb_learn, &G_Conf.midiInStartStop); + new gLearner(8, 56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec); + new gLearner(8, 80, w()-16, "input recording", &cb_learn, &G_Conf.midiInInputRec); + new gLearner(8, 104, w()-16, "metronome", &cb_learn, &G_Conf.midiInMetronome); + new gLearner(8, 128, w()-16, "input volume", &cb_learn, &G_Conf.midiInVolumeIn); + new gLearner(8, 152, w()-16, "output volume", &cb_learn, &G_Conf.midiInVolumeOut); + new gLearner(8, 176, w()-16, "sequencer ×2", &cb_learn, &G_Conf.midiInBeatDouble); + new gLearner(8, 200, w()-16, "sequencer ÷2", &cb_learn, &G_Conf.midiInBeatHalf); + ok = new gButton(w()-88, 228, 80, 20, "Close"); + + ok->callback(cb_close, (void*)this); + + gu_setFavicon(this); + show(); +} diff --git a/src/gd_midiInput.h b/src/gd_midiInput.h new file mode 100644 index 0000000..91bdea1 --- /dev/null +++ b/src/gd_midiInput.h @@ -0,0 +1,98 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiInput + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#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 items; for future use, with vst parameters + + static void cb_enable (Fl_Widget *w, void *p); + inline void __cb_enable(); + +public: + + gdMidiInputChannel(class Channel *ch); +}; + + +/* -------------------------------------------------------------------------- */ + + +class gdMidiInputMaster : public gdMidiInput +{ +public: + + gdMidiInputMaster(); +}; + + +#endif diff --git a/src/gd_midiOutput.cpp b/src/gd_midiOutput.cpp new file mode 100644 index 0000000..b01f6f6 --- /dev/null +++ b/src/gd_midiOutput.cpp @@ -0,0 +1,249 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiOutput + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "gd_midiOutput.h" +#include "ge_mixed.h" +#include "ge_channel.h" +#include "ge_midiIoTools.h" +#include "gg_keyboard.h" +#include "channel.h" +#include "sampleChannel.h" +#include "conf.h" +#include "midiChannel.h" +#include "gui_utils.h" + + +extern Conf G_Conf; + + +gdMidiOutput::gdMidiOutput(int w, int h) + //: gWindow(300, 64, "Midi Output Setup") + : gWindow(w, h, "Midi Output Setup") +{ +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::stopMidiLearn(gLearner *learner) { + kernelMidi::stopMidiLearn(); + learner->updateValue(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { + *param = msg; + stopMidiLearn(l); + gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::cb_learn(uint32_t msg, void *d) { + cbData *data = (cbData*) d; + gdMidiOutput *window = (gdMidiOutput*) data->window; + gLearner *learner = data->learner; + uint32_t *param = learner->param; + window->__cb_learn(param, msg, learner); + free(data); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutput*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::__cb_close() { + do_callback(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p) { + ((gdMidiOutput*)p)->__cb_enableLightning(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::__cb_enableLightning() {} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutput::setTitle(int chanNum) +{ + char title[64]; + sprintf(title, "MIDI Output Setup (channel %d)", chanNum); + copy_label(title); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch) + : gdMidiOutput(300, 168), ch(ch) +{ + setTitle(ch->index+1); + begin(); + + enableOut = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output"); + chanListOut = new gChoice(w()-108, y()+8, 100, 20); + + enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output"); + new gLearner(x()+8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); + new gLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); + new gLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); + + close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); + + end(); + + chanListOut->add("Channel 1"); + chanListOut->add("Channel 2"); + chanListOut->add("Channel 3"); + chanListOut->add("Channel 4"); + chanListOut->add("Channel 5"); + chanListOut->add("Channel 6"); + chanListOut->add("Channel 7"); + chanListOut->add("Channel 8"); + chanListOut->add("Channel 9"); + chanListOut->add("Channel 10"); + chanListOut->add("Channel 11"); + chanListOut->add("Channel 12"); + chanListOut->add("Channel 13"); + chanListOut->add("Channel 14"); + chanListOut->add("Channel 15"); + chanListOut->add("Channel 16"); + chanListOut->value(0); + + if (ch->midiOut) + enableOut->value(1); + else + chanListOut->deactivate(); + + if (ch->midiOutL) + enableLightning->value(1); + + chanListOut->value(ch->midiOutChan); + + enableOut->callback(cb_enableChanList, (void*)this); + close->callback(cb_close, (void*)this); + + set_modal(); + gu_setFavicon(this); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::cb_close (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); } +void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::__cb_enableChanList() { + enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputMidiCh::__cb_close() { + ch->midiOut = enableOut->value(); + ch->midiOutChan = chanListOut->value(); + ch->midiOutL = enableLightning->value(); + ch->guiChannel->update(); + do_callback(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch) + : gdMidiOutput(300, 140), ch(ch) +{ + setTitle(ch->index+1); + + enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output"); + new gLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); + new gLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); + new gLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); + + close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); + close->callback(cb_close, (void*)this); + + enableLightning->value(ch->midiOutL); + enableLightning->callback(cb_enableLightning, (void*)this); + + set_modal(); + gu_setFavicon(this); + show(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); } + + +/* -------------------------------------------------------------------------- */ + + +void gdMidiOutputSampleCh::__cb_close() { + ch->midiOutL = enableLightning->value(); + do_callback(); +} diff --git a/src/gd_midiOutput.h b/src/gd_midiOutput.h new file mode 100644 index 0000000..8dd2fd6 --- /dev/null +++ b/src/gd_midiOutput.h @@ -0,0 +1,134 @@ +/* ---------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * gd_midiOutput + * + * --------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * ------------------------------------------------------------------ */ + + +#ifndef GD_MIDI_OUTPUT_H +#define GD_MIDI_OUTPUT_H + + +#include +#include +#include "ge_window.h" + + +/* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI +output master is managed by the configuration window, hence gdMidiOutput deals +only with channels. + +Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set. +In addition MidiOutputMidiCh has the MIDI message output box. */ + +/* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another +parent class gdMidiIO to inherit from */ + +class gdMidiOutput : public gWindow +{ +protected: + + class gClick *close; + class gCheck *enableLightning; + + void stopMidiLearn(class gLearner *l); + + /* cb_learn + * callback attached to kernelMidi to learn various actions. */ + + static void cb_learn (uint32_t msg, void *data); + inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l); + + /* cb_close + close current window. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + + /* cb_enableLightning + enable MIDI lightning output. */ + + static void cb_enableLightning (Fl_Widget *w, void *p); + inline void __cb_enableLightning(); + + /* setTitle + * set window title. */ + + void setTitle(int chanNum); + +public: + + gdMidiOutput(int w, int h); +}; + + +/* -------------------------------------------------------------------------- */ + + +class gdMidiOutputMidiCh : public gdMidiOutput +{ +private: + + static void cb_enableChanList (Fl_Widget *w, void *p); + inline void __cb_enableChanList(); + + /* __cb_close + override parent method, we need to do more stuff on close. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + + class gCheck *enableOut; + class gChoice *chanListOut; + + class MidiChannel *ch; + +public: + + gdMidiOutputMidiCh(class MidiChannel *ch); +}; + + +/* -------------------------------------------------------------------------- */ + + +class gdMidiOutputSampleCh : public gdMidiOutput +{ +private: + + class SampleChannel *ch; + + /* __cb_close + override parent method, we need to do more stuff on close. */ + + static void cb_close (Fl_Widget *w, void *p); + inline void __cb_close(); + +public: + + gdMidiOutputSampleCh(class SampleChannel *ch); +}; + +#endif diff --git a/src/gd_midiOutputSetup.cpp b/src/gd_midiOutputSetup.cpp deleted file mode 100644 index 6cc0024..0000000 --- a/src/gd_midiOutputSetup.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiOutputSetup - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#include "gd_midiOutputSetup.h" -#include "ge_mixed.h" -#include "gg_keyboard.h" -#include "ge_channel.h" -#include "channel.h" -#include "conf.h" -#include "midiChannel.h" -#include "gui_utils.h" - - -extern Conf G_Conf; - - -gdMidiOutputSetup::gdMidiOutputSetup(MidiChannel *ch) - : gWindow(300, 64, "Midi Output Setup"), ch(ch) -{ - begin(); - enableOut = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output"); - chanListOut = new gChoice(w()-108, y()+8, 100, 20); - - save = new gButton(w()-88, chanListOut->y()+chanListOut->h()+8, 80, 20, "Save"); - cancel = new gButton(w()-88-save->w()-8, save->y(), 80, 20, "Cancel"); - end(); - - fillChanMenu(chanListOut); - - if (ch->midiOut) - enableOut->value(1); - else - chanListOut->deactivate(); - - chanListOut->value(ch->midiOutChan); - - enableOut->callback(cb_enableChanList, (void*)this); - save->callback(cb_save, (void*)this); - cancel->callback(cb_cancel, (void*)this); - - set_modal(); - gu_setFavicon(this); - show(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiOutputSetup::cb_save (Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_save(); } -void gdMidiOutputSetup::cb_cancel (Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_cancel(); } -void gdMidiOutputSetup::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputSetup*)p)->__cb_enableChanList(); } - - -/* ------------------------------------------------------------------ */ - - -void gdMidiOutputSetup::__cb_enableChanList() { - enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiOutputSetup::__cb_save() { - ch->midiOut = enableOut->value(); - ch->midiOutChan = chanListOut->value(); - ch->guiChannel->update(); - do_callback(); -} - - -/* ------------------------------------------------------------------ */ - - -void gdMidiOutputSetup::__cb_cancel() { do_callback(); } - - -/* ------------------------------------------------------------------ */ - - -void gdMidiOutputSetup::fillChanMenu(gChoice *m) { - m->add("Channel 1"); - m->add("Channel 2"); - m->add("Channel 3"); - m->add("Channel 4"); - m->add("Channel 5"); - m->add("Channel 6"); - m->add("Channel 7"); - m->add("Channel 8"); - m->add("Channel 9"); - m->add("Channel 10"); - m->add("Channel 11"); - m->add("Channel 12"); - m->add("Channel 13"); - m->add("Channel 14"); - m->add("Channel 15"); - m->add("Channel 16"); - m->value(0); -} diff --git a/src/gd_midiOutputSetup.h b/src/gd_midiOutputSetup.h deleted file mode 100644 index 9acf603..0000000 --- a/src/gd_midiOutputSetup.h +++ /dev/null @@ -1,63 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * gd_midiOutputSetup - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#ifndef GD_MIDI_OUTPUT_SETUP_H -#define GD_MIDI_OUTPUT_SETUP_H - - -#include -#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 diff --git a/src/ge_channel.cpp b/src/ge_channel.cpp index d244ad6..71cfb38 100644 --- a/src/ge_channel.cpp +++ b/src/ge_channel.cpp @@ -1,10 +1,10 @@ -/* ----------------------------------------------------------------------------- +/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_channel * - * ----------------------------------------------------------------------------- + * --------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,19 +24,19 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * -------------------------------------------------------------------------- */ + * ------------------------------------------------------------------ */ #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" diff --git a/src/ge_midiChannel.cpp b/src/ge_midiChannel.cpp index d9dfbf4..33cd991 100644 --- a/src/ge_midiChannel.cpp +++ b/src/ge_midiChannel.cpp @@ -32,13 +32,13 @@ #include "ge_sampleChannel.h" #include "gd_mainWindow.h" #include "gd_keyGrabber.h" -#include "gd_midiGrabber.h" +#include "gd_midiInput.h" #include "gd_editor.h" #include "gd_actionEditor.h" #include "gd_warnings.h" #include "gd_browser.h" #include "gd_keyGrabber.h" -#include "gd_midiOutputSetup.h" +#include "gd_midiOutput.h" #include "gg_keyboard.h" #include "pluginHost.h" #include "mixer.h" @@ -228,13 +228,14 @@ void gMidiChannel::__cb_openMenu() return; } - if (strcmp(m->label(), "Setup MIDI output...") == 0) { - gu_openSubWindow(mainWin, new gdMidiOutputSetup(ch), 0); + if (strcmp(m->label(), "Setup MIDI input...") == 0) { + gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); return; } - if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch), 0); + if (strcmp(m->label(), "Setup MIDI output...") == 0) { + //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); + gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0); return; } } diff --git a/src/ge_midiIoTools.cpp b/src/ge_midiIoTools.cpp new file mode 100644 index 0000000..da9b873 --- /dev/null +++ b/src/ge_midiIoTools.cpp @@ -0,0 +1,105 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_midiIoTools + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include "ge_midiIoTools.h" +#include "ge_mixed.h" + + +gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param) + : Fl_Group(X, Y, W, 20), + callback(cb), + param (param) +{ + begin(); + text = new gBox(x(), y(), 156, 20, l); + value = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)"); + button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn"); + end(); + + text->box(G_BOX); + text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); + + value->box(G_BOX); + value->callback(cb_value, (void*)this); + value->when(FL_WHEN_RELEASE); + updateValue(); + + button->type(FL_TOGGLE_BUTTON); + button->callback(cb_button, (void*)this); +} + + +/* -------------------------------------------------------------------------- */ + + +void gLearner::updateValue() { + char buf[16]; + if (*param != 0x0) + snprintf(buf, 9, "0x%X", *param); + else + snprintf(buf, 16, "(not set)"); + value->copy_label(buf); + button->value(0); +} + + +/* -------------------------------------------------------------------------- */ + + +void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); } +void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); } + + +/* -------------------------------------------------------------------------- */ + + +void gLearner::__cb_value() { + if (Fl::event_button() == FL_RIGHT_MOUSE) { + *param = 0x0; + updateValue(); + } + /// TODO - elif (LEFT_MOUSE) : insert values by hand +} + + +/* -------------------------------------------------------------------------- */ + + +/* FIXME - do not malloc on each callback! do it on the constructor! */ + +void gLearner::__cb_button() { + if (button->value() == 1) { + cbData *data = (cbData*) malloc(sizeof(cbData)); + data->window = (gdMidiInput*) parent(); // parent = gdMidiGrabberChannel + data->learner = this; + kernelMidi::startMidiLearn(callback, (void*)data); + } + else + kernelMidi::stopMidiLearn(); +} diff --git a/src/ge_midiIoTools.h b/src/ge_midiIoTools.h new file mode 100644 index 0000000..bd52756 --- /dev/null +++ b/src/ge_midiIoTools.h @@ -0,0 +1,92 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ge_midiIoTools + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GE_LEARNER_H +#define GE_LEARNER_H + + +#include +#include +#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 diff --git a/src/ge_sampleChannel.cpp b/src/ge_sampleChannel.cpp index 11bc005..7d0f846 100644 --- a/src/ge_sampleChannel.cpp +++ b/src/ge_sampleChannel.cpp @@ -30,12 +30,12 @@ #include "ge_sampleChannel.h" #include "gd_mainWindow.h" #include "gd_keyGrabber.h" -#include "gd_midiGrabber.h" +#include "gd_midiInput.h" #include "gd_editor.h" #include "gd_actionEditor.h" #include "gd_warnings.h" #include "gd_browser.h" -#include "gd_midiOutputSetup.h" +#include "gd_midiOutput.h" #include "gg_keyboard.h" #include "pluginHost.h" #include "mixer.h" @@ -196,23 +196,24 @@ void gSampleChannel::__cb_openMenu() {"Export sample to file..."}, // 1 {"Setup keyboard input..."}, // 2 {"Setup MIDI input..."}, // 3 - {"Edit sample..."}, // 4 - {"Edit actions..."}, // 5 - {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 6 - {"All"}, // 7 - {"Mute"}, // 8 - {"Volume"}, // 9 - {"Start/Stop"}, // 10 - {0}, // 11 - {"Free channel"}, // 12 - {"Delete channel"}, // 13 + {"Setup MIDI output..."}, // 4 + {"Edit sample..."}, // 5 + {"Edit actions..."}, // 6 + {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 7 + {"All"}, // 8 + {"Mute"}, // 9 + {"Volume"}, // 10 + {"Start/Stop"}, // 11 + {0}, // 12 + {"Free channel"}, // 13 + {"Delete channel"}, // 14 {0} }; if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) { rclick_menu[1].deactivate(); - rclick_menu[4].deactivate(); - rclick_menu[12].deactivate(); + rclick_menu[5].deactivate(); + rclick_menu[13].deactivate(); } /* no 'clear actions' if there are no actions */ @@ -246,7 +247,12 @@ void gSampleChannel::__cb_openMenu() } if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch), 0); + gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); + return; + } + + if (strcmp(m->label(), "Setup MIDI output...") == 0) { + gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0); return; } diff --git a/src/glue.cpp b/src/glue.cpp index 7844175..60d0a17 100644 --- a/src/glue.cpp +++ b/src/glue.cpp @@ -795,6 +795,7 @@ void glue_setSoloOn(Channel *ch, bool gui) } ch->solo = !ch->solo; + ch->sendMidiLsolo(); /* mute all other channels and unmute this (if muted) */ @@ -858,6 +859,7 @@ void glue_setSoloOff(Channel *ch, bool gui) } ch->solo = !ch->solo; + ch->sendMidiLsolo(); if (!gui) { Fl::lock(); diff --git a/src/init.cpp b/src/init.cpp index 51915b7..beeab04 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * init * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -39,6 +39,7 @@ #include "conf.h" #include "pluginHost.h" #include "recorder.h" +#include "midiMapConf.h" #include "gd_mainWindow.h" #include "gui_utils.h" #include "gd_warnings.h" @@ -50,6 +51,7 @@ extern bool G_audio_status; extern bool G_quit; extern Patch G_Patch; extern Conf G_Conf; +extern MidiMapConf G_MidiMap; extern gdMainWindow *mainWin; #ifdef WITH_VST @@ -70,7 +72,7 @@ void init_prepareParser() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void init_prepareKernelAudio() @@ -88,7 +90,7 @@ void init_prepareKernelAudio() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void init_prepareKernelMIDI() @@ -99,7 +101,18 @@ void init_prepareKernelMIDI() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ + + +void init_prepareMidiMap() +{ + G_MidiMap.init(); + G_MidiMap.setDefault(); + G_MidiMap.readMap(G_Conf.midiMapPath); +} + + +/* -------------------------------------------------------------------------- */ void init_startGUI(int argc, char **argv) @@ -125,7 +138,7 @@ void init_startGUI(int argc, char **argv) ); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void init_startKernelAudio() @@ -139,7 +152,7 @@ void init_startKernelAudio() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void init_shutdown() diff --git a/src/init.h b/src/init.h index 42a1102..0824f65 100644 --- a/src/init.h +++ b/src/init.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * init * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef INIT_H @@ -42,6 +42,7 @@ void init_prepareParser(); void init_startGUI(int argc, char **argv); void init_prepareKernelAudio(); void init_prepareKernelMIDI(); +void init_prepareMidiMap(); void init_startKernelAudio(); void init_shutdown(); diff --git a/src/kernelMidi.cpp b/src/kernelMidi.cpp index 3a42424..1d4f99b 100644 --- a/src/kernelMidi.cpp +++ b/src/kernelMidi.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelMidi * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -35,15 +35,17 @@ #include "sampleChannel.h" #include "pluginHost.h" #include "conf.h" +#include "midiMapConf.h" #include "log.h" -extern bool G_midiStatus; -extern Conf G_Conf; -extern Mixer G_Mixer; +extern bool G_midiStatus; +extern Conf G_Conf; +extern Mixer G_Mixer; +extern MidiMapConf G_MidiMap; #ifdef WITH_VST -extern PluginHost G_PluginHost; +extern PluginHost G_PluginHost; #endif @@ -60,7 +62,7 @@ cb_midiLearn *cb_learn = NULL; void *cb_data = NULL; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void startMidiLearn(cb_midiLearn *cb, void *data) @@ -70,7 +72,7 @@ void startMidiLearn(cb_midiLearn *cb, void *data) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void stopMidiLearn() @@ -80,7 +82,7 @@ void stopMidiLearn() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void setApi(int _api) @@ -90,7 +92,7 @@ void setApi(int _api) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ int openOutDevice(int port) @@ -118,6 +120,19 @@ int openOutDevice(int port) try { midiOut->openPort(port, getOutPortName(port)); gLog("[KM] MIDI out port %d open\n", port); + + /* for each init command of MidiMap, send the init commands to the + external world. TODO 1 - we shold do that only if there is a map loaded + and available in MidiMap. + TODO 2 - move the map initialization to another function */ + + for(int i=0; i msg(1, 0x00); - //msg[0] = getB1(data); - //msg[1] = getB2(data); - //msg[2] = getB3(data); - std::vector msg(1, getB1(data)); msg.push_back(getB2(data)); msg.push_back(getB3(data)); midiOut->sendMessage(&msg); - //gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]); + gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void send(int b1, int b2, int b3) @@ -246,7 +256,7 @@ void send(int b1, int b2, int b3) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void callback(double t, std::vector *msg, void *data) @@ -255,7 +265,7 @@ void callback(double t, std::vector *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; isize(); i++) gLog("%X", (int) msg->at(i)); gLog("\n"); @@ -373,7 +383,7 @@ void callback(double t, std::vector *msg, void *data) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ std::string getRtMidiVersion() diff --git a/src/kernelMidi.h b/src/kernelMidi.h index b17bbeb..d446995 100644 --- a/src/kernelMidi.h +++ b/src/kernelMidi.h @@ -97,7 +97,7 @@ namespace kernelMidi { * master callback for input events. */ void callback(double t, std::vector *msg, void *data); - + std::string getRtMidiVersion(); } diff --git a/src/main.cpp b/src/main.cpp index 687fb05..e714162 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,6 +33,7 @@ #include "const.h" #include "patch.h" #include "conf.h" +#include "midiMapConf.h" #include "mixer.h" #include "mixerHandler.h" #include "kernelAudio.h" @@ -53,6 +54,7 @@ bool G_audio_status; bool G_midiStatus; Patch G_Patch; Conf G_Conf; +MidiMapConf G_MidiMap; gdMainWindow *mainWin; #ifdef WITH_VST @@ -68,6 +70,7 @@ int main(int argc, char **argv) { G_quit = false; init_prepareParser(); + init_prepareMidiMap(); init_prepareKernelAudio(); init_prepareKernelMIDI(); init_startGUI(argc, argv); diff --git a/src/midiChannel.cpp b/src/midiChannel.cpp index f1e43b7..6f38684 100644 --- a/src/midiChannel.cpp +++ b/src/midiChannel.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include "channel.h" @@ -55,18 +55,19 @@ MidiChannel::MidiChannel(int bufferSize) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ MidiChannel::~MidiChannel() {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ #ifdef WITH_VST -void MidiChannel::freeVstMidiEvents(bool init) { +void MidiChannel::freeVstMidiEvents(bool init) +{ if (events.numEvents == 0 && !init) return; memset(events.events, 0, sizeof(VstEvent*) * MAX_VST_EVENTS); @@ -77,30 +78,32 @@ void MidiChannel::freeVstMidiEvents(bool init) { #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ #ifdef WITH_VST -void MidiChannel::addVstMidiEvent(uint32_t msg) { +void MidiChannel::addVstMidiEvent(uint32_t msg) +{ addVstMidiEvent(G_PluginHost.createVstMidiEvent(msg)); } #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ #ifdef WITH_VST -void MidiChannel::addVstMidiEvent(VstMidiEvent *e) { - if (events.numEvents < MAX_VST_EVENTS) { +void MidiChannel::addVstMidiEvent(VstMidiEvent *e) +{ + if (events.numEvents < MAX_VST_EVENTS) { events.events[events.numEvents] = (VstEvent*) e; events.numEvents++; /* - gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n", - events.numEvents, + gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n", + events.numEvents, e->deltaFrames, e->midiData[0], e->midiData[1], @@ -114,87 +117,99 @@ void MidiChannel::addVstMidiEvent(VstMidiEvent *e) { #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void MidiChannel::onBar(int frame) {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void MidiChannel::stop() {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void MidiChannel::empty() {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void MidiChannel::quantize(int index, int localFrame, int globalFrame) {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ #ifdef WITH_VST -VstEvents *MidiChannel::getVstEvents() { +VstEvents *MidiChannel::getVstEvents() +{ return (VstEvents *) &events; } #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) { +void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) +{ if (a->type == ACTION_MIDI) sendMidi(a, localFrame/2); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::onZero(int frame) { - if (status == STATUS_ENDING) +void MidiChannel::onZero(int frame) +{ + if (status == STATUS_ENDING) { status = STATUS_OFF; + sendMidiLplay(); + } else - if (status == STATUS_WAIT) + if (status == STATUS_WAIT) { status = STATUS_PLAY; + sendMidiLplay(); + } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::setMute(bool internal) { +void MidiChannel::setMute(bool internal) +{ mute = true; // internal mute does not exist for midi (for now) if (midiOut) kernelMidi::send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST addVstMidiEvent(MIDI_ALL_NOTES_OFF); #endif + sendMidiLmute(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::unsetMute(bool internal) { +void MidiChannel::unsetMute(bool internal) +{ mute = false; // internal mute does not exist for midi (for now) + sendMidiLmute(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::process(float *buffer) { +void MidiChannel::process(float *buffer) +{ #ifdef WITH_VST G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this); freeVstMidiEvents(); @@ -207,37 +222,43 @@ void MidiChannel::process(float *buffer) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::start(int frame, bool doQuantize) { +void MidiChannel::start(int frame, bool doQuantize) +{ switch (status) { case STATUS_PLAY: status = STATUS_ENDING; + sendMidiLplay(); break; case STATUS_ENDING: case STATUS_WAIT: status = STATUS_OFF; + sendMidiLplay(); break; case STATUS_OFF: status = STATUS_WAIT; + sendMidiLplay(); break; } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::stopBySeq() { +void MidiChannel::stopBySeq() +{ kill(0); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::kill(int frame) { +void MidiChannel::kill(int frame) +{ if (status & (STATUS_PLAY | STATUS_ENDING)) { if (midiOut) kernelMidi::send(MIDI_ALL_NOTES_OFF); @@ -246,13 +267,15 @@ void MidiChannel::kill(int frame) { #endif } status = STATUS_OFF; + sendMidiLplay(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int MidiChannel::loadByPatch(const char *f, int i) { +int MidiChannel::loadByPatch(const char *f, int i) +{ volume = G_Patch.getVol(i); index = G_Patch.getIndex(i); mute = G_Patch.getMute(i); @@ -265,15 +288,16 @@ int MidiChannel::loadByPatch(const char *f, int i) { midiOutChan = G_Patch.getMidiValue(i, "OutChan"); readPatchMidiIn(i); + readPatchMidiOut(i); return SAMPLE_LOADED_OK; /// TODO - change name, it's meaningless here } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::sendMidi(recorder::action *a, int localFrame) +void MidiChannel::sendMidi(recorder::action *a, int localFrame) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { if (midiOut) @@ -287,7 +311,7 @@ void MidiChannel::sendMidi(recorder::action *a, int localFrame) } -void MidiChannel::sendMidi(uint32_t data) +void MidiChannel::sendMidi(uint32_t data) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { if (midiOut) @@ -299,10 +323,11 @@ void MidiChannel::sendMidi(uint32_t data) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void MidiChannel::rewind() { +void MidiChannel::rewind() +{ if (midiOut) kernelMidi::send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST @@ -311,7 +336,7 @@ void MidiChannel::rewind() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void MidiChannel::writePatch(FILE *fp, int i, bool isProject) diff --git a/src/midiMapConf.cpp b/src/midiMapConf.cpp new file mode 100644 index 0000000..7fa8268 --- /dev/null +++ b/src/midiMapConf.cpp @@ -0,0 +1,223 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * midiMapConf + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#include +#include +#include +#include +#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 ic; + gSplit(getValue("init_commands"), ";", &ic); + for (unsigned i=0; i. + * + * -------------------------------------------------------------------------- */ + + +#ifndef __MIDIMAPCONF_H__ +#define __MIDIMAPCONF_H__ + + +#include +#include +#include "dataStorage.h" +#include "utils.h" +#if defined(__APPLE__) +#include +#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 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 diff --git a/src/sampleChannel.cpp b/src/sampleChannel.cpp index 300db28..1b9cb29 100644 --- a/src/sampleChannel.cpp +++ b/src/sampleChannel.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2015 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include @@ -35,6 +35,7 @@ #include "pluginHost.h" #include "waveFx.h" #include "mixerHandler.h" +#include "kernelMidi.h" #include "log.h" @@ -72,10 +73,11 @@ SampleChannel::SampleChannel(int bufferSize) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -SampleChannel::~SampleChannel() { +SampleChannel::~SampleChannel() +{ if (wave) delete wave; src_delete(rsmp_state); @@ -83,11 +85,11 @@ SampleChannel::~SampleChannel() { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::clear() { +void SampleChannel::clear() +{ /** TODO - these memsets can be done only if status PLAY (if below), * but it would require extra clearPChan calls when samples stop */ @@ -104,11 +106,11 @@ void SampleChannel::clear() { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::calcVolumeEnv(int frame) { +void SampleChannel::calcVolumeEnv(int frame) +{ /* method: check this frame && next frame, then calculate delta */ recorder::action *a0 = NULL; @@ -137,21 +139,24 @@ void SampleChannel::calcVolumeEnv(int frame) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::hardStop(int frame) { +void SampleChannel::hardStop(int frame) +{ if (frame != 0) // clear data in range [frame, bufferSize-1] clearChan(vChan, frame); status = STATUS_OFF; + sendMidiLplay(); reset(frame); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::onBar(int frame) { +void SampleChannel::onBar(int frame) +{ ///if (mode == LOOP_REPEAT && status == STATUS_PLAY) /// //setXFade(frame); /// reset(frame); @@ -166,41 +171,45 @@ void SampleChannel::onBar(int frame) { if (status == STATUS_WAIT) { status = STATUS_PLAY; tracker = fillChan(vChan, tracker, frame); + sendMidiLplay(); } } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int SampleChannel::save(const char *path) { +int SampleChannel::save(const char *path) +{ return wave->writeData(path); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setBegin(unsigned v) { +void SampleChannel::setBegin(unsigned v) +{ begin = v; tracker = begin; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setEnd(unsigned v) { +void SampleChannel::setEnd(unsigned v) +{ end = v; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setPitch(float v) { - +void SampleChannel::setPitch(float v) +{ pitch = v; rsmp_data.src_ratio = 1/pitch; @@ -211,11 +220,11 @@ void SampleChannel::setPitch(float v) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::rewind() { - +void SampleChannel::rewind() +{ /* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */ if (wave != NULL) { @@ -225,11 +234,11 @@ void SampleChannel::rewind() { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) { +void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) +{ if (readActions == false) return; @@ -259,11 +268,11 @@ void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalF } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::sum(int frame, bool running) { +void SampleChannel::sum(int frame, bool running) +{ if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING)) return; @@ -349,14 +358,17 @@ void SampleChannel::sum(int frame, bool running) { (mode & LOOP_ANY && !running)) // stop loops when the seq is off { status = STATUS_OFF; + sendMidiLplay(); } /* temporary stop LOOP_ONCE not in ENDING status, otherwise they * would return in wait, losing the ENDING status */ //if (mode == LOOP_ONCE && status != STATUS_ENDING) - if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING) + if ((mode & (LOOP_ONCE | LOOP_ONCE_BAR)) && status != STATUS_ENDING) { status = STATUS_WAIT; + sendMidiLplay(); + } /* check for end of samples. SINGLE_ENDLESS runs forever unless * it's in ENDING mode. */ @@ -366,11 +378,11 @@ void SampleChannel::sum(int frame, bool running) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::onZero(int frame) { - +void SampleChannel::onZero(int frame) +{ if (wave == NULL) return; @@ -395,6 +407,7 @@ void SampleChannel::onZero(int frame) { if (status == STATUS_WAIT) { /// FIXME - should be inside previous if! status = STATUS_PLAY; + sendMidiLplay(); tracker = fillChan(vChan, tracker, frame); } @@ -410,11 +423,11 @@ void SampleChannel::onZero(int frame) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::quantize(int index, int localFrame, int globalFrame) { - +void SampleChannel::quantize(int index, int localFrame, int globalFrame) +{ /* skip if LOOP_ANY or not in quantizer-wait mode */ if ((mode & LOOP_ANY) || !qWait) @@ -425,6 +438,7 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) { if (status == STATUS_OFF) { status = STATUS_PLAY; + sendMidiLplay(); qWait = false; tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ??? } @@ -444,10 +458,11 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int SampleChannel::getPosition() { +int SampleChannel::getPosition() +{ if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...) return tracker - begin; else @@ -455,11 +470,11 @@ int SampleChannel::getPosition() { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::setMute(bool internal) { +void SampleChannel::setMute(bool internal) +{ if (internal) { /* global mute is on? don't waste time with fadeout, just mute it @@ -491,13 +506,16 @@ void SampleChannel::setMute(bool internal) { mute = true; } } + + sendMidiLmute(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::unsetMute(bool internal) { +void SampleChannel::unsetMute(bool internal) +{ if (internal) { if (mute) mute_i = false; @@ -518,13 +536,16 @@ void SampleChannel::unsetMute(bool internal) { mute = false; } } + + sendMidiLmute(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::calcFadeoutStep() { +void SampleChannel::calcFadeoutStep() +{ if (end - tracker < (1 / DEFAULT_FADEOUT_STEP) * 2) fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ??? else @@ -532,10 +553,11 @@ void SampleChannel::calcFadeoutStep() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setReadActions(bool v) { +void SampleChannel::setReadActions(bool v) +{ if (v) readActions = true; else { @@ -546,10 +568,11 @@ void SampleChannel::setReadActions(bool v) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setFadeIn(bool internal) { +void SampleChannel::setFadeIn(bool internal) +{ if (internal) mute_i = false; // remove mute before fading in else mute = false; fadeinOn = true; @@ -557,10 +580,11 @@ void SampleChannel::setFadeIn(bool internal) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::setFadeOut(int actionPostFadeout) { +void SampleChannel::setFadeOut(int actionPostFadeout) +{ calcFadeoutStep(); fadeoutOn = true; fadeoutVol = 1.0f; @@ -569,11 +593,11 @@ void SampleChannel::setFadeOut(int actionPostFadeout) { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::setXFade(int frame) { +void SampleChannel::setXFade(int frame) +{ gLog("[xFade] frame=%d tracker=%d\n", frame, tracker); calcFadeoutStep(); @@ -585,7 +609,7 @@ void SampleChannel::setXFade(int frame) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ /* on reset, if frame > 0 and in play, fill again pChan to create @@ -596,7 +620,8 @@ void SampleChannel::setXFade(int frame) { * * */ -void SampleChannel::reset(int frame) { +void SampleChannel::reset(int frame) +{ //fadeoutTracker = tracker; // store old frame number for xfade tracker = begin; mute_i = false; @@ -605,35 +630,39 @@ void SampleChannel::reset(int frame) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::empty() { +void SampleChannel::empty() +{ status = STATUS_OFF; if (wave) { delete wave; wave = NULL; } status = STATUS_EMPTY; + sendMidiLplay(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::pushWave(Wave *w) { +void SampleChannel::pushWave(Wave *w) +{ wave = w; status = STATUS_OFF; + sendMidiLplay(); begin = 0; end = wave->size; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -bool SampleChannel::allocEmpty(int frames, int takeId) { - +bool SampleChannel::allocEmpty(int frames, int takeId) +{ Wave *w = new Wave(); if (!w->allocEmpty(frames)) return false; @@ -648,15 +677,17 @@ bool SampleChannel::allocEmpty(int frames, int takeId) { begin = 0; end = wave->size; + sendMidiLplay(); + return true; } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::process(float *buffer) { +void SampleChannel::process(float *buffer) +{ #ifdef WITH_VST G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this); #endif @@ -668,10 +699,11 @@ void SampleChannel::process(float *buffer) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::kill(int frame) { +void SampleChannel::kill(int frame) +{ if (wave != NULL && status != STATUS_OFF) { if (mute || mute_i || (status == STATUS_WAIT && mode & LOOP_ANY)) hardStop(frame); @@ -681,11 +713,11 @@ void SampleChannel::kill(int frame) { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::stopBySeq() { +void SampleChannel::stopBySeq() +{ /* kill loop channels and recs if "samplesStopOnSeqHalt" == true, * else do nothing and return. Always kill at frame=0, this is a * user-generated event. */ @@ -710,10 +742,11 @@ void SampleChannel::stopBySeq() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::stop() { +void SampleChannel::stop() +{ if (mode == SINGLE_PRESS && status == STATUS_PLAY) { if (mute || mute_i) hardStop(0); /// FIXME - wrong frame value @@ -726,11 +759,11 @@ void SampleChannel::stop() { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int SampleChannel::load(const char *file) { - +int SampleChannel::load(const char *file) +{ if (strcmp(file, "") == 0 || gIsDir(file)) { gLog("[SampleChannel] file not specified\n"); return SAMPLE_LEFT_EMPTY; @@ -783,11 +816,11 @@ int SampleChannel::load(const char *file) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int SampleChannel::loadByPatch(const char *f, int i) { - +int SampleChannel::loadByPatch(const char *f, int i) +{ int res = load(f); volume = G_Patch.getVol(i); @@ -806,6 +839,7 @@ int SampleChannel::loadByPatch(const char *f, int i) { readPatchMidiIn(i); midiInReadActions = G_Patch.getMidiValue(i, "InReadActions"); midiInPitch = G_Patch.getMidiValue(i, "InPitch"); + readPatchMidiOut(i); if (res == SAMPLE_LOADED_OK) { setBegin(G_Patch.getBegin(i)); @@ -823,25 +857,27 @@ int SampleChannel::loadByPatch(const char *f, int i) { else if (res == SAMPLE_READ_ERROR) status = STATUS_MISSING; + sendMidiLplay(); } return res; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -bool SampleChannel::canInputRec() { +bool SampleChannel::canInputRec() + { return wave == NULL; } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void SampleChannel::start(int frame, bool doQuantize) { +void SampleChannel::start(int frame, bool doQuantize) +{ switch (status) { case STATUS_EMPTY: case STATUS_MISSING: @@ -854,6 +890,7 @@ void SampleChannel::start(int frame, bool doQuantize) { { if (mode & LOOP_ANY) { status = STATUS_WAIT; + sendMidiLplay(); } else { if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize) @@ -864,6 +901,7 @@ void SampleChannel::start(int frame, bool doQuantize) { * a duplicate call to fillChan occurs with loss of data. */ status = STATUS_PLAY; + sendMidiLplay(); if (frame != 0) tracker = fillChan(vChan, tracker, frame); } @@ -883,31 +921,35 @@ void SampleChannel::start(int frame, bool doQuantize) { reset(frame); } else - if (mode & (LOOP_ANY | SINGLE_ENDLESS)) + if (mode & (LOOP_ANY | SINGLE_ENDLESS)) { status = STATUS_ENDING; + sendMidiLplay(); + } break; } case STATUS_WAIT: { status = STATUS_OFF; + sendMidiLplay(); break; } case STATUS_ENDING: { status = STATUS_PLAY; + sendMidiLplay(); break; } } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::writePatch(FILE *fp, int i, bool isProject) { - +void SampleChannel::writePatch(FILE *fp, int i, bool isProject) +{ Channel::writePatch(fp, i, isProject); const char *path = ""; @@ -932,19 +974,20 @@ void SampleChannel::writePatch(FILE *fp, int i, bool isProject) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void SampleChannel::clearChan(float *dest, int start) { +void SampleChannel::clearChan(float *dest, int start) +{ memset(dest+start, 0, sizeof(float)*(bufferSize-start)); } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind) { +int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind) +{ int position; // return value: the new position if (pitch == 1.0f) {