From ae30bd633d2221840c6db5359a6e97f21d0a074c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jarom=C3=ADr=20Mike=C5=A1?= Date: Mon, 21 Nov 2016 09:32:09 +0100 Subject: [PATCH] New upstream version 0.13.1~dfsg1 --- ChangeLog | 25 +- Makefile.am | 90 +- src/core/channel.cpp | 67 +- src/core/channel.h | 84 +- src/core/conf.cpp | 20 +- src/core/const.h | 14 +- src/core/dataStorageIni.cpp | 2 +- src/core/dataStorageJson.cpp | 18 +- src/core/graphics.cpp | 110 +- src/core/graphics.h | 14 +- src/core/init.cpp | 111 +- src/core/kernelAudio.cpp | 184 ++-- src/core/kernelAudio.h | 56 +- src/core/kernelMidi.cpp | 292 +++--- src/core/kernelMidi.h | 75 +- src/core/midiChannel.cpp | 92 +- src/core/midiChannel.h | 64 +- src/core/midiMapConf.cpp | 40 +- src/core/midiMapConf.h | 2 +- src/core/mixer.cpp | 574 ++++++----- src/core/mixer.h | 91 +- src/core/mixerHandler.cpp | 108 +- src/core/mixerHandler.h | 19 +- src/core/patch.cpp | 26 +- src/core/patch.h | 3 +- src/core/patch_DEPR_.cpp | 21 +- src/core/plugin.cpp | 8 +- src/core/pluginHost.cpp | 146 ++- src/core/pluginHost.h | 7 +- src/core/recorder.cpp | 134 ++- src/core/recorder.h | 212 ++-- src/core/sampleChannel.cpp | 120 ++- src/core/sampleChannel.h | 58 +- src/core/wave.cpp | 32 +- src/core/waveFx.cpp | 70 +- src/core/waveFx.h | 6 +- src/glue/channel.cpp | 386 ++++++- src/glue/channel.h | 42 +- src/glue/glue.cpp | 972 ------------------ src/glue/glue.h | 148 --- src/glue/io.cpp | 327 ++++++ src/glue/io.h | 67 ++ src/glue/main.cpp | 421 ++++++++ src/glue/main.h | 81 ++ src/glue/storage.cpp | 79 +- src/glue/storage.h | 9 +- src/gui/dialogs/gd_about.cpp | 11 +- src/gui/dialogs/gd_about.h | 15 +- src/gui/dialogs/gd_actionEditor.cpp | 18 +- src/gui/dialogs/gd_actionEditor.h | 12 +- src/gui/dialogs/gd_beatsInput.cpp | 5 +- src/gui/dialogs/gd_bpmInput.cpp | 5 +- src/gui/dialogs/gd_browser.cpp | 13 +- src/gui/dialogs/gd_config.cpp | 89 +- src/gui/dialogs/gd_config.h | 14 +- src/gui/dialogs/gd_devInfo.cpp | 28 +- src/gui/dialogs/gd_editor.cpp | 93 +- src/gui/dialogs/gd_editor.h | 16 +- src/gui/dialogs/gd_keyGrabber.cpp | 10 +- src/gui/dialogs/gd_mainWindow.cpp | 119 +-- src/gui/dialogs/gd_mainWindow.h | 14 +- src/gui/dialogs/gd_midiInput.cpp | 58 +- src/gui/dialogs/gd_midiInput.h | 8 +- src/gui/dialogs/gd_midiOutput.cpp | 37 +- src/gui/dialogs/gd_pluginChooser.cpp | 2 +- src/gui/dialogs/gd_pluginList.cpp | 21 +- src/gui/dialogs/gd_pluginWindow.cpp | 2 +- src/gui/dialogs/gd_pluginWindowGUI.cpp | 10 +- src/gui/dialogs/gd_warnings.h | 2 +- ...{ge_actionChannel.cpp => actionEditor.cpp} | 71 +- .../{ge_actionChannel.h => actionEditor.h} | 8 +- ..._actionWidget.cpp => baseActionEditor.cpp} | 19 +- .../{ge_actionWidget.h => baseActionEditor.h} | 18 +- src/gui/elems/{ge_channel.cpp => channel.cpp} | 146 ++- src/gui/elems/{ge_channel.h => channel.h} | 68 +- ...ge_channelButton.cpp => channelButton.cpp} | 22 +- .../{ge_channelButton.h => channelButton.h} | 4 +- ...envelopeChannel.cpp => envelopeEditor.cpp} | 70 +- ...{ge_envelopeChannel.h => envelopeEditor.h} | 14 +- src/gui/elems/ge_browser.cpp | 14 +- src/gui/elems/ge_column.cpp | 39 +- src/gui/elems/ge_column.h | 4 +- src/gui/elems/ge_controller.cpp | 11 +- src/gui/elems/ge_keyboard.cpp | 35 +- src/gui/elems/ge_keyboard.h | 20 +- src/gui/elems/ge_midiIoTools.cpp | 12 +- src/gui/elems/ge_midiIoTools.h | 8 +- src/gui/elems/ge_mixed.cpp | 4 +- src/gui/elems/ge_mixed.h | 1 + src/gui/elems/ge_modeBox.cpp | 2 +- src/gui/elems/ge_pianoRoll.cpp | 730 ------------- src/gui/elems/ge_status.cpp | 8 +- src/gui/elems/ge_waveTools.cpp | 8 +- src/gui/elems/ge_waveform.cpp | 5 +- src/gui/elems/ge_waveform.h | 2 +- src/gui/elems/ge_window.cpp | 8 +- src/gui/elems/ge_window.h | 2 +- .../{ge_midiChannel.cpp => midiChannel.cpp} | 143 +-- .../elems/{ge_midiChannel.h => midiChannel.h} | 32 +- .../{ge_muteChannel.cpp => muteEditor.cpp} | 85 +- .../elems/{ge_muteChannel.h => muteEditor.h} | 20 +- src/gui/elems/noteEditor.cpp | 90 ++ src/gui/elems/noteEditor.h | 54 + src/gui/elems/pianoItem.cpp | 348 +++++++ src/gui/elems/{ge_pianoRoll.h => pianoItem.h} | 110 +- src/gui/elems/pianoRoll.cpp | 360 +++++++ src/gui/elems/pianoRoll.h | 84 ++ ...ge_sampleChannel.cpp => sampleChannel.cpp} | 309 ++---- .../{ge_sampleChannel.h => sampleChannel.h} | 43 +- src/main.cpp | 26 +- src/utils/{utils.cpp => fs.cpp} | 200 +--- src/utils/{utils.h => fs.h} | 44 +- src/utils/{gui_utils.cpp => gui.cpp} | 82 +- src/utils/{gui_utils.h => gui.h} | 12 +- src/utils/log.cpp | 26 +- src/utils/log.h | 14 +- src/utils/string.cpp | 61 +- src/utils/string.h | 14 +- tests/patch.cpp | 2 + tests/pluginHost.cpp | 4 + tests/utils.cpp | 31 +- 121 files changed, 5137 insertions(+), 4539 deletions(-) delete mode 100644 src/glue/glue.cpp delete mode 100644 src/glue/glue.h create mode 100644 src/glue/io.cpp create mode 100644 src/glue/io.h create mode 100644 src/glue/main.cpp create mode 100644 src/glue/main.h rename src/gui/elems/{ge_actionChannel.cpp => actionEditor.cpp} (89%) rename src/gui/elems/{ge_actionChannel.h => actionEditor.h} (95%) rename src/gui/elems/{ge_actionWidget.cpp => baseActionEditor.cpp} (89%) rename src/gui/elems/{ge_actionWidget.h => baseActionEditor.h} (84%) rename src/gui/elems/{ge_channel.cpp => channel.cpp} (51%) rename src/gui/elems/{ge_channel.h => channel.h} (60%) rename src/gui/elems/{ge_channelButton.cpp => channelButton.cpp} (85%) rename src/gui/elems/{ge_channelButton.h => channelButton.h} (93%) rename src/gui/elems/{ge_envelopeChannel.cpp => envelopeEditor.cpp} (81%) rename src/gui/elems/{ge_envelopeChannel.h => envelopeEditor.h} (93%) delete mode 100644 src/gui/elems/ge_pianoRoll.cpp rename src/gui/elems/{ge_midiChannel.cpp => midiChannel.cpp} (64%) rename src/gui/elems/{ge_midiChannel.h => midiChannel.h} (66%) rename src/gui/elems/{ge_muteChannel.cpp => muteEditor.cpp} (79%) rename src/gui/elems/{ge_muteChannel.h => muteEditor.h} (89%) create mode 100644 src/gui/elems/noteEditor.cpp create mode 100644 src/gui/elems/noteEditor.h create mode 100644 src/gui/elems/pianoItem.cpp rename src/gui/elems/{ge_pianoRoll.h => pianoItem.h} (54%) create mode 100644 src/gui/elems/pianoRoll.cpp create mode 100644 src/gui/elems/pianoRoll.h rename src/gui/elems/{ge_sampleChannel.cpp => sampleChannel.cpp} (57%) rename src/gui/elems/{ge_sampleChannel.h => sampleChannel.h} (62%) rename src/utils/{utils.cpp => fs.cpp} (55%) rename src/utils/{utils.h => fs.h} (57%) rename src/utils/{gui_utils.cpp => gui.cpp} (70%) rename src/utils/{gui_utils.h => gui.h} (95%) diff --git a/ChangeLog b/ChangeLog index abcbc3f..22878ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,7 +12,26 @@ -------------------------------------------------------------------------------- -0.13.0 --- +0.13.1 --- 2016 . 11 . 16 +- Input MIDI to MIDI channels/plugins +- Refinements to show/hide 'R' button's dynamics +- Increase piano roll items' height +- Set input volume to max by default +- Start live-recorded sample channels right away +- Avoid potential crashes when loading samples on running channels +- Generate metronome during output post-processing +- Better widgets' layout in Sample Editor +- Lots of source code optimizations and cleanups +- Fix inverted 'R' button's status (GitHub #94) +- Better handling of 'R' button's status when the sequencer is off (GitHub #95) +- Fix non-playing samples if live-recorded and 'R' button is on (GitHub #93) +- Reset button statuses once channels have been freed (GitHub #100) +- Fix missing ASIO and WASAPI APIs on Windows (GitHub #96) +- Missing RtMidi libs on Linux (GitHub #102) +- Fix fade-in/fade-out editing not triggering alert on save (GitHub #101) + + +0.13.0 --- 2016 . 09 . 20 - Deep file browser refactoring - Save browser's scroll position and last item selected on opening - Load patches/projects/samples on double click @@ -25,9 +44,13 @@ - Update JUCE to version 4.2.3 - Don't include JUCE on tests without VST support (GitHub #75) - Fix compilation errors on GCC 6 (GitHub #82) +- Fix includes on OSX (GitHub #92) - Fix wrong channel's actions count that prevented "R" button to be toggled properly - Fixed a bug that prevented actions on frame 0 to being properly reproduced +- Make Recorder a proper class +- Better naming convention for ActionEditor's children classes +- Source code reorganization 0.12.2 --- 2016 . 06 . 02 diff --git a/Makefile.am b/Makefile.am index a78f094..7990158 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,8 +47,10 @@ src/core/dataStorageIni.h \ src/core/dataStorageIni.cpp \ src/core/dataStorageJson.h \ src/core/dataStorageJson.cpp \ -src/glue/glue.h \ -src/glue/glue.cpp \ +src/glue/main.h \ +src/glue/main.cpp \ +src/glue/io.h \ +src/glue/io.cpp \ src/glue/storage.h \ src/glue/storage.cpp \ src/glue/channel.h \ @@ -89,10 +91,10 @@ src/gui/dialogs/gd_pluginChooser.h \ src/gui/dialogs/gd_pluginChooser.cpp \ src/gui/elems/ge_column.h \ src/gui/elems/ge_column.cpp \ -src/gui/elems/ge_sampleChannel.h \ -src/gui/elems/ge_sampleChannel.cpp \ -src/gui/elems/ge_midiChannel.h \ -src/gui/elems/ge_midiChannel.cpp \ +src/gui/elems/sampleChannel.h \ +src/gui/elems/sampleChannel.cpp \ +src/gui/elems/midiChannel.h \ +src/gui/elems/midiChannel.cpp \ src/gui/elems/ge_midiIoTools.h \ src/gui/elems/ge_midiIoTools.cpp \ src/gui/elems/ge_mixed.h \ @@ -101,18 +103,22 @@ src/gui/elems/ge_waveform.h \ src/gui/elems/ge_waveform.cpp \ src/gui/elems/ge_browser.h \ src/gui/elems/ge_browser.cpp \ -src/gui/elems/ge_actionWidget.h \ -src/gui/elems/ge_actionWidget.cpp \ -src/gui/elems/ge_envelopeChannel.h \ -src/gui/elems/ge_envelopeChannel.cpp \ -src/gui/elems/ge_pianoRoll.h \ -src/gui/elems/ge_pianoRoll.cpp \ -src/gui/elems/ge_channel.h \ -src/gui/elems/ge_channel.cpp \ -src/gui/elems/ge_muteChannel.h \ -src/gui/elems/ge_muteChannel.cpp \ -src/gui/elems/ge_actionChannel.h \ -src/gui/elems/ge_actionChannel.cpp \ +src/gui/elems/baseActionEditor.h \ +src/gui/elems/baseActionEditor.cpp \ +src/gui/elems/envelopeEditor.h \ +src/gui/elems/envelopeEditor.cpp \ +src/gui/elems/pianoRoll.h \ +src/gui/elems/pianoRoll.cpp \ +src/gui/elems/noteEditor.h \ +src/gui/elems/noteEditor.cpp \ +src/gui/elems/pianoItem.h \ +src/gui/elems/pianoItem.cpp \ +src/gui/elems/channel.h \ +src/gui/elems/channel.cpp \ +src/gui/elems/muteEditor.h \ +src/gui/elems/muteEditor.cpp \ +src/gui/elems/actionEditor.h \ +src/gui/elems/actionEditor.cpp \ src/gui/elems/ge_window.h \ src/gui/elems/ge_window.cpp \ src/gui/elems/ge_status.h \ @@ -125,17 +131,17 @@ src/gui/elems/ge_modeBox.h \ src/gui/elems/ge_modeBox.cpp \ src/gui/elems/ge_controller.h \ src/gui/elems/ge_controller.cpp \ -src/gui/elems/ge_channelButton.h \ -src/gui/elems/ge_channelButton.cpp \ +src/gui/elems/channelButton.h \ +src/gui/elems/channelButton.cpp \ src/gui/elems/ge_pluginBrowser.h \ src/gui/elems/ge_pluginBrowser.cpp \ src/utils/log.h \ src/utils/log.cpp \ -src/utils/gui_utils.h \ -src/utils/gui_utils.cpp \ +src/utils/gui.h \ +src/utils/gui.cpp \ src/utils/gvector.h \ -src/utils/utils.h \ -src/utils/utils.cpp \ +src/utils/fs.h \ +src/utils/fs.cpp \ src/utils/string.h \ src/utils/string.cpp @@ -176,13 +182,13 @@ giada_CPPFLAGS += \ -DJUCE_PLUGINHOST_VST=1 \ -DJUCE_PLUGINHOST_VST3=0 \ -DJUCE_PLUGINHOST_AU=0 -giada_CXXFLAGS += -Wno-error=misleading-indentation endif if LINUX giada_SOURCES += src/deps/rtaudio-mod/RtAudio.h src/deps/rtaudio-mod/RtAudio.cpp -# mute rtAudio error on variable length array -giada_CXXFLAGS += -Wno-error=vla +# -Wno-error=vla: mute rtAudio error on variable length array +# -Wno-error=misleading-indentation: mute JUCE warnings on GCC6 +giada_CXXFLAGS += -Wno-error=vla -Wno-error=misleading-indentation giada_CPPFLAGS += -D__LINUX_ALSA__ -D__LINUX_PULSE__ -D__UNIX_JACK__ giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \ -lpthread -ldl -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson \ @@ -190,7 +196,28 @@ giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \ endif if WINDOWS -giada_LDADD = -lrtaudio -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \ +giada_SOURCES += \ +src/deps/rtaudio-mod/RtAudio.h \ +src/deps/rtaudio-mod/RtAudio.cpp \ +src/deps/rtaudio-mod/include/asio.h \ +src/deps/rtaudio-mod/include/asio.cpp \ +src/deps/rtaudio-mod/include/asiolist.h \ +src/deps/rtaudio-mod/include/asiolist.cpp \ +src/deps/rtaudio-mod/include/asiodrivers.h \ +src/deps/rtaudio-mod/include/asiodrivers.cpp \ +src/deps/rtaudio-mod/include/iasiothiscallresolver.h \ +src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp +# -Wno-error=misleading-indentation: mute JUCE warnings on GCC6 +# -Wno-error=unused-but-set-variable: silence ASIO errors +giada_CXXFLAGS += \ +-Wno-error=misleading-indentation \ +-Wno-error=unused-but-set-variable +giada_CPPFLAGS += \ +-I./src/deps/rtaudio-mod/include \ +-D__WINDOWS_ASIO__ \ +-D__WINDOWS_WASAPI__ \ +-D__WINDOWS_DS__ +giada_LDADD = -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \ -lshell32 -lvfw32 -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 -lsndfile \ -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser -lpthreadGC2 -ljansson \ -limm32 -lglu32 -lshell32 -lversion -lopengl32 -loleaut32 -lshlwapi -lcomdlg32 @@ -203,8 +230,9 @@ if OSX # export CXXFLAGS="-m32" # export LDFLAGS="-m32" # -ObjC++: Juce requires to build some Objective C code +# -Wno-unknown-pragmas: shut up Juce even more giada_SOURCES += src/utils/cocoa.mm src/utils/cocoa.h -giada_CXXFLAGS += -ObjC++ +giada_CXXFLAGS += -ObjC++ -Wno-unknown-pragmas giada_LDADD = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \ -lsamplerate -ljansson giada_LDFLAGS = -framework CoreAudio -framework Cocoa -framework Carbon \ @@ -234,10 +262,10 @@ src/core/wave.cpp \ src/core/midiMapConf.cpp \ src/core/patch.cpp \ src/core/plugin.cpp \ -src/core/pluginHost.cpp \ src/core/dataStorageIni.cpp \ src/core/dataStorageJson.cpp \ -src/utils/utils.cpp \ +src/utils/fs.cpp \ +src/utils/string.cpp \ src/utils/log.cpp if WITH_VST diff --git a/src/core/channel.cpp b/src/core/channel.cpp index 1a3204a..bcbafeb 100644 --- a/src/core/channel.cpp +++ b/src/core/channel.cpp @@ -28,7 +28,7 @@ #include "../utils/log.h" -#include "../gui/elems/ge_channel.h" +#include "../gui/elems/channel.h" #include "channel.h" #include "pluginHost.h" #include "plugin.h" @@ -44,9 +44,13 @@ #include "midiMapConf.h" +extern Recorder G_Recorder; +extern KernelMidi G_KernelMidi; + + Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf) #if defined(WITH_VST) -: pluginHost(NULL), +: pluginHost(nullptr), #else : #endif @@ -65,13 +69,15 @@ Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf) mute (false), solo (false), hasActions (false), + armed (false), recStatus (REC_STOPPED), - vChan (NULL), - guiChannel (NULL), + vChan (nullptr), + guiChannel (nullptr), midiIn (true), midiInKeyPress (0x0), midiInKeyRel (0x0), midiInKill (0x0), + midiInArm (0x0), midiInVolume (0x0), midiInMute (0x0), midiInSolo (0x0), @@ -82,7 +88,7 @@ Channel::Channel(int type, int status, int bufferSize, MidiMapConf *midiMapConf) { vChan = (float *) malloc(bufferSize * sizeof(float)); if (!vChan) - gLog("[Channel::allocVchan] unable to alloc memory for vChan\n"); + gu_log("[Channel::allocVchan] unable to alloc memory for vChan\n"); memset(vChan, 0, bufferSize * sizeof(float)); } @@ -119,6 +125,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex) midiInKeyPress = src->midiInKeyPress; midiInKeyRel = src->midiInKeyRel; midiInKill = src->midiInKill; + midiInArm = src->midiInArm; midiInVolume = src->midiInVolume; midiInMute = src->midiInMute; midiInSolo = src->midiInSolo; @@ -137,11 +144,11 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex) /* clone actions */ - for (unsigned i=0; ichan == src->index) - recorder::rec(index, a->type, a->frame, a->iValue, a->fValue); + G_Recorder.rec(index, a->type, a->frame, a->iValue, a->fValue); } } } @@ -152,7 +159,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex) void Channel::sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg) { - gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n", + gu_log("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n", learn, msg.channel, msg.value, msg.offset); /* isolate 'channel' from learnt message and offset it as requested by 'nn' @@ -164,7 +171,7 @@ void Channel::sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg * send it. */ out |= msg.value | (msg.channel << 24); - kernelMidi::send(out); + G_KernelMidi.send(out); } @@ -220,6 +227,7 @@ int Channel::writePatch(int i, bool isProject, Patch *patch) pch.midiInKeyPress = midiInKeyPress; pch.midiInKeyRel = midiInKeyRel; pch.midiInKill = midiInKill; + pch.midiInArm = midiInArm; pch.midiInVolume = midiInVolume; pch.midiInMute = midiInMute; pch.midiInSolo = midiInSolo; @@ -228,9 +236,9 @@ int Channel::writePatch(int i, bool isProject, Patch *patch) pch.midiOutLmute = midiOutLmute; pch.midiOutLsolo = midiOutLsolo; - for (unsigned i=0; ichan == index) { Patch::action_t pac; pac.type = action->type; @@ -296,7 +304,7 @@ int Channel::readPatch(const string &path, int i, Patch *patch, for (unsigned k=0; kactions.size(); k++) { Patch::action_t *ac = &pch->actions.at(k); - recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue); + G_Recorder.rec(index, ac->type, ac->frame, ac->iValue, ac->fValue); } #ifdef WITH_VST @@ -305,7 +313,7 @@ int Channel::readPatch(const string &path, int i, Patch *patch, Patch::plugin_t *ppl = &pch->plugins.at(k); Plugin *plugin = pluginHost->addPlugin(ppl->path, PluginHost::CHANNEL, pluginMutex, this); - if (plugin != NULL) { + if (plugin != nullptr) { plugin->setBypass(ppl->bypass); for (unsigned j=0; jparams.size(); j++) plugin->setParameter(j, ppl->params.at(j)); @@ -375,9 +383,36 @@ void Channel::sendMidiLplay() /* -------------------------------------------------------------------------- */ +void Channel::receiveMidi(uint32_t msg) +{ +} + +/* -------------------------------------------------------------------------- */ + + #ifdef WITH_VST + +juce::MidiBuffer &Channel::getPluginMidiEvents() +{ + return midiBuffer; +} + + +/* -------------------------------------------------------------------------- */ + + +void Channel::clearMidiBuffer() +{ + midiBuffer.clear(); +} + + +/* -------------------------------------------------------------------------- */ + + void Channel::setPluginHost(PluginHost *pluginHost) { this->pluginHost = pluginHost; } + #endif diff --git a/src/core/channel.h b/src/core/channel.h index e0ee899..df9fe64 100644 --- a/src/core/channel.h +++ b/src/core/channel.h @@ -32,15 +32,15 @@ #include -#include "../utils/utils.h" +#include #include "midiMapConf.h" -#include "const.h" #include "recorder.h" #ifdef WITH_VST #include "../deps/juce/config.h" #endif + using std::vector; using std::string; @@ -91,12 +91,6 @@ public: virtual void copy(const Channel *src, pthread_mutex_t *pluginMutex) = 0; - /* writePatch - * Fill a patch with channel values. Returns the index of the last - * Patch::channel_t added. */ - - virtual int writePatch(int i, bool isProject, class Patch *patch); - /* readPatch * Fill channel with data from patch. */ @@ -106,16 +100,19 @@ public: pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality); /* process - * merge vChannels into buffer, plus plugin processing (if any). */ + Merges vChannels into buffer, plus plugin processing (if any). Warning: + inBuffer might be nullptr if no input devices are available for recording. */ - virtual void process(float *buffer) = 0; + virtual void process(float *outBuffer, float *inBuffer) = 0; /* start - * action to do when channel starts. doQuantize = false (don't - * quantize) when Mixer is reading actions from Recorder::. */ + Action to do when channel starts. doQuantize = false (don't quantize) + when Mixer is reading actions from Recorder. If isUserGenerated means that + the channel has been started by a human key press and not a pre-recorded + action. */ virtual void start(int frame, bool doQuantize, int quantize, - bool mixerIsRunning) = 0; + bool mixerIsRunning, bool forceStart, bool isUserGenerated) = 0; /* stop * action to do when channel is stopped normally (via key or MIDI). */ @@ -167,7 +164,9 @@ public: * localFrame - frame number of the processed buffer * globalFrame - actual frame in Mixer */ - virtual void parseAction(recorder::action *a, int localFrame, int globalFrame, + // TODO - quantize is useless! + + virtual void parseAction(Recorder::action *a, int localFrame, int globalFrame, int quantize, bool mixerIsRunning) = 0; /* rewind @@ -175,25 +174,49 @@ public: virtual void rewind() = 0; + /* clear + Clears all memory buffers. This is actually useful to sample channels only. */ + + virtual void clear() = 0; + + /* canInputRec + Tells whether a channel can accept and handle input audio. Always false for + Midi channels, true for Sample channels only if they don't contain a + sample yet.*/ + + virtual bool canInputRec() = 0; + + /* writePatch + * Fill a patch with channel values. Returns the index of the last + * Patch::channel_t added. */ + + virtual int writePatch(int i, bool isProject, class Patch *patch); + + /* receiveMidi + * Receives and processes midi messages from external devices. */ + + virtual void receiveMidi(uint32_t msg); + /* ------------------------------------------------------------------------ */ - int index; // unique id - int type; // midi or sample - int status; // status: see const.h - int key; // keyboard button - float volume; // global volume - float volume_i; // internal volume - float volume_d; // delta volume (for envelope) + int index; // unique id + int type; // midi or sample + int status; // status: see const.h + int key; // keyboard button + float volume; // global volume + float volume_i; // internal volume + float volume_d; // delta volume (for envelope) float panLeft; float panRight; - bool mute_i; // internal mute - bool mute_s; // previous mute status after being solo'd - bool mute; // global mute + bool mute_i; // internal mute + bool mute_s; // previous mute status after being solo'd + bool mute; // global mute bool solo; - bool hasActions; // has something recorded - int recStatus; // status of recordings (waiting, ending, ...) - float *vChan; // virtual channel - class gChannel *guiChannel; // pointer to a gChannel object, part of the GUI + bool hasActions; // has something recorded + bool armed; // armed for recording + int recStatus; // status of recordings (waiting, ending, ...) + float *vChan; // virtual channel + class geChannel *guiChannel; // pointer to a gChannel object, part of the GUI // TODO - midi structs, please @@ -201,6 +224,7 @@ public: uint32_t midiInKeyPress; uint32_t midiInKeyRel; uint32_t midiInKill; + uint32_t midiInArm; uint32_t midiInVolume; uint32_t midiInMute; uint32_t midiInSolo; @@ -253,7 +277,9 @@ public: * Return a reference to midiBuffer stack. This is available for any kind of * channel, but it makes sense only for MIDI channels. */ - juce::MidiBuffer &getPluginMidiEvents() { return midiBuffer; }; + juce::MidiBuffer &getPluginMidiEvents(); + + void clearMidiBuffer(); #endif }; diff --git a/src/core/conf.cpp b/src/core/conf.cpp index eadbce2..021549b 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -30,7 +30,7 @@ #include #include "conf.h" #include "const.h" -#include "../utils/utils.h" +#include "../utils/fs.h" #include "../utils/log.h" @@ -44,8 +44,8 @@ Conf::Conf() #if defined(__linux__) || defined(__APPLE__) - confFilePath = gGetHomePath() + G_SLASH + CONF_FILENAME; - confDirPath = gGetHomePath() + G_SLASH; + confFilePath = gu_getHomePath() + G_SLASH + CONF_FILENAME; + confDirPath = gu_getHomePath() + G_SLASH; #elif defined(_WIN32) @@ -63,17 +63,17 @@ int Conf::createConfigFolder() { #if defined(__linux__) || defined(__APPLE__) - if (gDirExists(confDirPath)) + if (gu_dirExists(confDirPath)) return 1; - gLog("[Conf::createConfigFolder] .giada folder not present. Updating...\n"); + gu_log("[Conf::createConfigFolder] .giada folder not present. Updating...\n"); - if (gMkdir(confDirPath)) { - gLog("[Conf::createConfigFolder] status: ok\n"); + if (gu_mkdir(confDirPath)) { + gu_log("[Conf::createConfigFolder] status: ok\n"); return 1; } else { - gLog("[Conf::createConfigFolder] status: error!\n"); + gu_log("[Conf::createConfigFolder] status: error!\n"); return 0; } @@ -178,7 +178,7 @@ int Conf::read() jRoot = json_load_file(confFilePath.c_str(), 0, &jError); if (!jRoot) { - gLog("[Conf::read] unable to read configuration file! Error on line %d: %s\n", jError.line, jError.text); + gu_log("[Conf::read] unable to read configuration file! Error on line %d: %s\n", jError.line, jError.text); return 0; } @@ -373,7 +373,7 @@ int Conf::write() #endif if (json_dump_file(jRoot, confFilePath.c_str(), JSON_INDENT(2)) != 0) { - gLog("[Conf::write] unable to write configuration file!\n"); + gu_log("[Conf::write] unable to write configuration file!\n"); return 0; } return 1; diff --git a/src/core/const.h b/src/core/const.h index 90b362f..9571b2d 100644 --- a/src/core/const.h +++ b/src/core/const.h @@ -32,11 +32,11 @@ /* -- version --------------------------------------------------------------- */ -#define G_VERSION_STR "0.13.0" +#define G_VERSION_STR "0.13.1" #define G_APP_NAME "Giada" #define G_VERSION_MAJOR 0 #define G_VERSION_MINOR 13 -#define G_VERSION_PATCH 0 +#define G_VERSION_PATCH 1 #define CONF_FILENAME "giada.conf" @@ -75,6 +75,8 @@ #define COLOR_TEXT_0 fl_rgb_color(200, 200, 200) #define COLOR_TEXT_1 fl_rgb_color(25, 25, 25) // TODO - duplicate! #define COLOR_BG_MAIN fl_rgb_color(25, 25, 25) // windows background +#define COLOR_BG_RICH fl_rgb_color(30, 30, 30) // lighter background +#define COLOR_BG_LINE fl_rgb_color(54, 54, 54) // lighter, for bg lines #define COLOR_BG_DARK fl_rgb_color(0, 0, 0) // inputs background @@ -128,11 +130,11 @@ #define DEFAULT_SAMPLERATE 44100 #define DEFAULT_BUFSIZE 1024 #define DEFAULT_DELAYCOMP 0 -#define DEFAULT_VOL 0.0f +#define DEFAULT_VOL 1.0f #define DEFAULT_BOOST 0.0f #define gDEFAULT_PITCH 1.0f // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only). #define DEFAULT_OUT_VOL 1.0f -#define DEFAULT_IN_VOL 0.0f +#define DEFAULT_IN_VOL 1.0f #define DEFAULT_CHANMODE SINGLE_BASIC #define DEFAULT_BPM 120.0f #define DEFAULT_BEATS 4 @@ -140,6 +142,7 @@ #define DEFAULT_QUANTIZE 0 // quantizer off #define DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed #define DEFAULT_COLUMN_WIDTH 380 +#define G_DEFAULT_PATCH_NAME "(default patch)" @@ -211,6 +214,7 @@ /* -- browser types --------------------------------------------------------- */ +/* TODO - USELESS, remove them */ #define BROWSER_LOAD_PATCH 0x00 #define BROWSER_LOAD_SAMPLE 0x01 #define BROWSER_SAVE_PATCH 0x02 @@ -268,6 +272,7 @@ #define MIDI_CONTROLLER 0xB0 << 24 #define MIDI_NOTE_ON 0x90 << 24 #define MIDI_NOTE_OFF 0x80 << 24 +#define MIDI_VELOCITY 0x3F << 8 #define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16) #define MIDI_VOLUME (MIDI_CONTROLLER) | (0x07 << 16) @@ -350,6 +355,7 @@ const int MIDI_CHANS[16] = { #define PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS "midi_in_keypress" #define PATCH_KEY_CHANNEL_MIDI_IN_KEYREL "midi_in_keyrel" #define PATCH_KEY_CHANNEL_MIDI_IN_KILL "midi_in_kill" +#define PATCH_KEY_CHANNEL_MIDI_IN_ARM "midi_in_arm" #define PATCH_KEY_CHANNEL_MIDI_IN_VOLUME "midi_in_volume" #define PATCH_KEY_CHANNEL_MIDI_IN_MUTE "midi_in_mute" #define PATCH_KEY_CHANNEL_MIDI_IN_SOLO "midi_in_solo" diff --git a/src/core/dataStorageIni.cpp b/src/core/dataStorageIni.cpp index 5b4a5ec..a759782 100644 --- a/src/core/dataStorageIni.cpp +++ b/src/core/dataStorageIni.cpp @@ -47,7 +47,7 @@ std::string DataStorageIni::getValue(const char *in) char buffer[MAX_LINE_LEN]; if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) { - gLog("[DataStorageIni::getValue] key '%s' not found\n", in); + gu_log("[DataStorageIni::getValue] key '%s' not found\n", in); return ""; } diff --git a/src/core/dataStorageJson.cpp b/src/core/dataStorageJson.cpp index 0a48542..a52f142 100644 --- a/src/core/dataStorageJson.cpp +++ b/src/core/dataStorageJson.cpp @@ -39,7 +39,7 @@ bool DataStorageJson::setString(json_t *jRoot, const char *key, string &output) { json_t *jObject = json_object_get(jRoot, key); if (!json_is_string(jObject)) { - gLog("[dataStorageJson::setString] key '%s' is not a string!\n", key); + gu_log("[dataStorageJson::setString] key '%s' is not a string!\n", key); json_decref(jRoot); return false; } @@ -55,12 +55,12 @@ bool DataStorageJson::setFloat(json_t *jRoot, const char *key, float &output) { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { - gLog("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key); + gu_log("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key); output = 0.0f; return true; } if (!json_is_real(jObject)) { - gLog("[dataStorageJson::setFloat] key '%s' is not a float!\n", key); + gu_log("[dataStorageJson::setFloat] key '%s' is not a float!\n", key); json_decref(jRoot); return false; } @@ -76,12 +76,12 @@ bool DataStorageJson::setUint32(json_t *jRoot, const char *key, uint32_t &output { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { - gLog("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key); + gu_log("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key); output = 0; return true; } if (!json_is_integer(jObject)) { - gLog("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key); + gu_log("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key); json_decref(jRoot); return false; } @@ -97,12 +97,12 @@ bool DataStorageJson::setBool(json_t *jRoot, const char *key, bool &output) { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { - gLog("[dataStorageJson::setBool] key '%s' not found, using default value\n", key); + gu_log("[dataStorageJson::setBool] key '%s' not found, using default value\n", key); output = false; return true; } if (!json_is_boolean(jObject)) { - gLog("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key); + gu_log("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key); json_decref(jRoot); return false; } @@ -126,7 +126,7 @@ bool DataStorageJson::setInt(json_t *jRoot, const char *key, int &output) bool DataStorageJson::checkObject(json_t *jRoot, const char *key) { if (!json_is_object(jRoot)) { - gLog("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key); + gu_log("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key); json_decref(jRoot); return false; } @@ -140,7 +140,7 @@ bool DataStorageJson::checkObject(json_t *jRoot, const char *key) bool DataStorageJson::checkArray(json_t *jRoot, const char *key) { if (!json_is_array(jRoot)) { - gLog("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key); + gu_log("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key); json_decref(jRoot); return false; } diff --git a/src/core/graphics.cpp b/src/core/graphics.cpp index b5b9402..2826793 100644 --- a/src/core/graphics.cpp +++ b/src/core/graphics.cpp @@ -785,6 +785,48 @@ const char *inputRecOff_xpm[] = { " ", " "}; +const char *inputToOutputOn_xpm[] = { +"10 10 8 1", +" c #4D4F4C", +". c #585A57", +"+ c #666765", +"@ c #6F716E", +"# c #939592", +"$ c #999B98", +"% c #AEB0AD", +"& c #BCBEBB", +" ", +" ", +" .#@ ", +" #&&#+ ", +" @$&%. ", +" @$&%. ", +" #&&#+ ", +" .#@ ", +" ", +" "}; + +const char *inputToOutputOff_xpm[] = { +"10 10 8 1", +" c #242523", +". c #2E302D", +"+ c #3A3B39", +"@ c #4F514E", +"# c #828481", +"$ c #8B8D8A", +"% c #A7A9A6", +"& c #B9BBB7", +" ", +" ", +" +$@ ", +" .#&&#+ ", +" @$&%. ", +" @$&%. ", +" .#&&#+ ", +" +$@ ", +" ", +" "}; + const char *muteOff_xpm[] = { "18 18 8 1", " c #242523", @@ -1512,7 +1554,7 @@ const char *fxRemoveOn_xpm[] = { #endif // #ifdef WITH_VST -const char *beatsDivideOn_xpm[] = { +const char *divideOn_xpm[] = { "18 18 7 1", " c #5A5A5A", ". c #696969", @@ -1541,7 +1583,7 @@ const char *beatsDivideOn_xpm[] = { " "}; -const char *beatsDivideOff_xpm[] = { +const char *divideOff_xpm[] = { "18 18 8 1", " c #252525", ". c #3B3B3B", @@ -1571,7 +1613,7 @@ const char *beatsDivideOff_xpm[] = { " "}; -const char *beatsMultiplyOn_xpm[] = { +const char *multiplyOn_xpm[] = { "18 18 8 1", " c #595B58", ". c #737572", @@ -1601,7 +1643,7 @@ const char *beatsMultiplyOn_xpm[] = { " "}; -const char *beatsMultiplyOff_xpm[] = { +const char *multiplyOff_xpm[] = { "18 18 8 1", " c #242523", ". c #4A4C49", @@ -1690,3 +1732,63 @@ const char *channelPlay_xpm[] = { " ", " ", " "}; + + +const char *armOff_xpm[] = { +"18 18 8 1", +" c #242523", +". c #4F4445", +"+ c #514647", +"@ c #6D5C5E", +"# c #8E7372", +"$ c #AA8889", +"% c #AC898A", +"& c #B18E8F", +" ", +" ", +" ", +" ", +" +#%%#. ", +" @&&&&&&@ ", +" +&&&&&&&&. ", +" #&&&&&&&&# ", +" %&&&&&&&&% ", +" %&&&&&&&&% ", +" #&&&&&&&&# ", +" .&&&&&&&&. ", +" @&&&&&&@ ", +" .#%%#. ", +" ", +" ", +" ", +" "}; + + +const char *armOn_xpm[] = { +"18 18 8 1", +" c #4D4F4C", +". c #6B5077", +"+ c #805191", +"@ c #9950AD", +"# c #9751B3", +"$ c #9553AD", +"% c #AA52C9", +"& c #AE52D1", +" ", +" ", +" ", +" ", +" .#%%#. ", +" +&&&&&&+ ", +" .&&&&&&&&. ", +" #&&&&&&&&@ ", +" %&&&&&&&&% ", +" %&&&&&&&&% ", +" #&&&&&&&&$ ", +" .&&&&&&&&. ", +" +&&&&&&+ ", +" .@%%$. ", +" ", +" ", +" ", +" "}; diff --git a/src/core/graphics.h b/src/core/graphics.h index 39fde45..7d93be8 100644 --- a/src/core/graphics.h +++ b/src/core/graphics.h @@ -68,10 +68,13 @@ extern const char *metronomeOn_xpm[]; extern const char *inputRecOn_xpm[]; extern const char *inputRecOff_xpm[]; -extern const char *beatsDivideOn_xpm[]; -extern const char *beatsDivideOff_xpm[]; -extern const char *beatsMultiplyOn_xpm[]; -extern const char *beatsMultiplyOff_xpm[]; +extern const char *inputToOutputOn_xpm[]; +extern const char *inputToOutputOff_xpm[]; + +extern const char *divideOn_xpm[]; +extern const char *divideOff_xpm[]; +extern const char *multiplyOn_xpm[]; +extern const char *multiplyOff_xpm[]; extern const char *muteOff_xpm[]; extern const char *muteOn_xpm[]; @@ -79,6 +82,9 @@ extern const char *muteOn_xpm[]; extern const char *soloOff_xpm[]; extern const char *soloOn_xpm[]; +extern const char *armOff_xpm[]; +extern const char *armOn_xpm[]; + extern const char *readActionOn_xpm[]; extern const char *readActionOff_xpm[]; diff --git a/src/core/init.cpp b/src/core/init.cpp index d0771c5..e280d46 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -29,8 +29,8 @@ #include #include "../utils/log.h" -#include "../utils/utils.h" -#include "../utils/gui_utils.h" +#include "../utils/fs.h" +#include "../utils/gui.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_warnings.h" #include "init.h" @@ -47,14 +47,17 @@ #include "kernelMidi.h" +extern KernelAudio G_KernelAudio; extern Mixer G_Mixer; +extern Recorder G_Recorder; +extern KernelMidi G_KernelMidi; extern bool G_audio_status; extern bool G_quit; extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Conf G_Conf; extern MidiMapConf G_MidiMap; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; #ifdef WITH_VST extern PluginHost G_PluginHost; @@ -65,24 +68,16 @@ void init_prepareParser() { time_t t; time (&t); - gLog("[init] Giada " G_VERSION_STR " - %s", ctime(&t)); + gu_log("[init] Giada " G_VERSION_STR " - %s", ctime(&t)); G_Conf.read(); G_Patch_DEPR_.setDefault(); G_Patch.init(); -#ifdef WITH_VST - - G_PluginHost.init(G_Conf.buffersize, G_Conf.samplerate); - G_PluginHost.sortPlugins(G_Conf.pluginSortMethod); - -#endif + if (!gu_logInit(G_Conf.logMode)) + gu_log("[init] log init failed! Using default stdout\n"); - - if (!gLog_init(G_Conf.logMode)) - gLog("[init] log init failed! Using default stdout\n"); - - gLog("[init] configuration file ready\n"); + gu_log("[init] configuration file ready\n"); } @@ -91,16 +86,25 @@ void init_prepareParser() void init_prepareKernelAudio() { - kernelAudio::openDevice( - G_Conf.soundSystem, - G_Conf.soundDeviceOut, - G_Conf.soundDeviceIn, - G_Conf.channelsOut, - G_Conf.channelsIn, - G_Conf.samplerate, - G_Conf.buffersize); + G_KernelAudio.openDevice(G_Conf.soundSystem, G_Conf.soundDeviceOut, + G_Conf.soundDeviceIn, G_Conf.channelsOut, G_Conf.channelsIn, + G_Conf.samplerate, G_Conf.buffersize); G_Mixer.init(); - recorder::init(); + G_Recorder.init(); + +#ifdef WITH_VST + + /* If with Jack don't use buffer size stored in Conf. Use real buffersize + from the soundcard (G_KernelAudio.realBufsize). */ + + if (G_Conf.soundSystem == SYS_API_JACK) + G_PluginHost.init(G_KernelAudio.realBufsize, G_Conf.samplerate); + else + G_PluginHost.init(G_Conf.buffersize, G_Conf.samplerate); + + G_PluginHost.sortPlugins(G_Conf.pluginSortMethod); + +#endif } @@ -109,9 +113,9 @@ void init_prepareKernelAudio() void init_prepareKernelMIDI() { - kernelMidi::setApi(G_Conf.midiSystem); - kernelMidi::openOutDevice(G_Conf.midiPortOut); - kernelMidi::openInDevice(G_Conf.midiPortIn); + G_KernelMidi.setApi(G_Conf.midiSystem); + G_KernelMidi.openOutDevice(G_Conf.midiPortOut); + G_KernelMidi.openInDevice(G_Conf.midiPortIn); } @@ -128,9 +132,9 @@ void init_prepareMidiMap() // TODO - do the opposite: if json fails, go with deprecated one if (G_MidiMap.read(G_Conf.midiMapPath) != MIDIMAP_READ_OK) { - gLog("[init_prepareMidiMap] JSON-based midimap read failed, trying with the deprecated one...\n"); + gu_log("[init_prepareMidiMap] JSON-based midimap read failed, trying with the deprecated one...\n"); if (G_MidiMap.readMap_DEPR_(G_Conf.midiMapPath) == MIDIMAP_INVALID) - gLog("[init_prepareMidiMap] unable to read deprecated midimap. Nothing to do\n"); + gu_log("[init_prepareMidiMap] unable to read deprecated midimap. Nothing to do\n"); } } @@ -140,25 +144,20 @@ void init_prepareMidiMap() void init_startGUI(int argc, char **argv) { - char win_label[32]; - sprintf(win_label, "%s - %s", - G_APP_NAME, - !strcmp(G_Patch_DEPR_.name, "") ? "(default patch)" : G_Patch_DEPR_.name); + G_MainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, "", argc, argv); + G_MainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, + G_Conf.mainWindowH); - mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv); - mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH); + gu_updateMainWinLabel(G_Patch.name == "" ? G_DEFAULT_PATCH_NAME : G_Patch.name); /* never update the GUI elements if G_audio_status is bad, segfaults * are around the corner */ if (G_audio_status) gu_updateControls(); - - if (!G_audio_status) - gdAlert( - "Your soundcard isn't configured correctly.\n" - "Check the configuration and restart Giada." - ); + else + gdAlert("Your soundcard isn't configured correctly.\n" + "Check the configuration and restart Giada."); } /* -------------------------------------------------------------------------- */ @@ -167,7 +166,7 @@ void init_startGUI(int argc, char **argv) void init_startKernelAudio() { if (G_audio_status) - kernelAudio::startStream(); + G_KernelAudio.startStream(); } @@ -180,41 +179,41 @@ void init_shutdown() /* store position and size of the main window for the next startup */ - G_Conf.mainWindowX = mainWin->x(); - G_Conf.mainWindowY = mainWin->y(); - G_Conf.mainWindowW = mainWin->w(); - G_Conf.mainWindowH = mainWin->h(); + G_Conf.mainWindowX = G_MainWin->x(); + G_Conf.mainWindowY = G_MainWin->y(); + G_Conf.mainWindowW = G_MainWin->w(); + G_Conf.mainWindowH = G_MainWin->h(); /* close any open subwindow, especially before cleaning PluginHost_DEPR_ to * avoid mess */ gu_closeAllSubwindows(); - gLog("[init] all subwindows closed\n"); + gu_log("[init] all subwindows closed\n"); /* write configuration file */ if (!G_Conf.write()) - gLog("[init] error while saving configuration file!\n"); + gu_log("[init] error while saving configuration file!\n"); else - gLog("[init] configuration saved\n"); + gu_log("[init] configuration saved\n"); /* if G_audio_status we close the kernelAudio FIRST, THEN the mixer. * The opposite could cause random segfaults (even now with RtAudio?). */ if (G_audio_status) { - kernelAudio::closeDevice(); + G_KernelAudio.closeDevice(); G_Mixer.close(); - gLog("[init] Mixer closed\n"); + gu_log("[init] Mixer closed\n"); } - recorder::clearAll(); - gLog("[init] Recorder cleaned up\n"); + G_Recorder.clearAll(); + gu_log("[init] Recorder cleaned up\n"); #ifdef WITH_VST G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins); - gLog("[init] PluginHost cleaned up\n"); + gu_log("[init] PluginHost cleaned up\n"); #endif - gLog("[init] Giada " G_VERSION_STR " closed\n\n"); - gLog_close(); + gu_log("[init] Giada " G_VERSION_STR " closed\n\n"); + gu_logClose(); } diff --git a/src/core/kernelAudio.cpp b/src/core/kernelAudio.cpp index d9dbb0e..b487df9 100644 --- a/src/core/kernelAudio.cpp +++ b/src/core/kernelAudio.cpp @@ -27,40 +27,43 @@ * -------------------------------------------------------------------------- */ -#include -#include #include "../utils/log.h" -#include "../glue/glue.h" -#include "kernelAudio.h" +#include "../glue/main.h" +#include "conf.h" #include "mixer.h" +#include "const.h" +#include "kernelAudio.h" -#include "conf.h" + +extern KernelAudio G_KernelAudio; +extern Mixer G_Mixer; +extern Conf G_Conf; +extern bool G_audio_status; -extern Mixer G_Mixer; -extern Conf G_Conf; -extern bool G_audio_status; +using std::string; +using std::vector; -namespace kernelAudio +KernelAudio::KernelAudio() { -RtAudio *system = NULL; -unsigned numDevs = 0; -bool inputEnabled = 0; -unsigned realBufsize = 0; -int api = 0; - -int openDevice( - int _api, - int outDev, - int inDev, - int outChan, - int inChan, - int samplerate, - int buffersize) + system = nullptr; + numDevs = 0; + inputEnabled = 0; + realBufsize = 0; + api = 0; +} + + +/* -------------------------------------------------------------------------- */ + + + +int KernelAudio::openDevice(int _api, int outDev, int inDev, int outChan, + int inChan, int samplerate, int buffersize) { api = _api; - gLog("[KA] using system 0x%x\n", api); + gu_log("[KA] using system 0x%x\n", api); #if defined(__linux__) @@ -88,7 +91,7 @@ int openDevice( if (api == SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE)) system = new RtAudio(RtAudio::MACOSX_CORE); - + #endif else { @@ -96,27 +99,22 @@ int openDevice( return 0; } - - - //gLog("[KA] %d\n", sizeof(system->rtapi_)); - - gLog("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate); + gu_log("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate); numDevs = system->getDeviceCount(); if (numDevs < 1) { - gLog("[KA] no devices found with this API\n"); + gu_log("[KA] no devices found with this API\n"); closeDevice(); G_audio_status = false; return 0; } else { - gLog("[KA] %d device(s) found\n", numDevs); + gu_log("[KA] %d device(s) found\n", numDevs); for (unsigned i=0; iopenStream( - &outParams, // output params - inDev != -1 ? &inParams : NULL, // input params if inDevice is selected - RTAUDIO_FLOAT32, // audio format - samplerate, // sample rate - &realBufsize, // buffer size in byte - &G_Mixer.masterPlay, // audio callback - NULL, // user data (unused) + &outParams, // output params + inDev != -1 ? &inParams : nullptr, // input params if inDevice is selected + RTAUDIO_FLOAT32, // audio format + samplerate, // sample rate + &realBufsize, // buffer size in byte + &G_Mixer.masterPlay, // audio callback + nullptr, // user data (unused) &options); G_audio_status = true; @@ -173,7 +171,7 @@ int openDevice( return 1; } catch (RtAudioError &e) { - gLog("[KA] system init error: %s\n", e.getMessage().c_str()); + gu_log("[KA] system init error: %s\n", e.getMessage().c_str()); closeDevice(); G_audio_status = false; return 0; @@ -184,15 +182,15 @@ int openDevice( /* -------------------------------------------------------------------------- */ -int startStream() +int KernelAudio::startStream() { try { system->startStream(); - gLog("[KA] latency = %lu\n", system->getStreamLatency()); + gu_log("[KA] latency = %lu\n", system->getStreamLatency()); return 1; } catch (RtAudioError &e) { - gLog("[KA] Start stream error: %s\n", e.getMessage().c_str()); + gu_log("[KA] Start stream error: %s\n", e.getMessage().c_str()); return 0; } } @@ -201,14 +199,14 @@ int startStream() /* -------------------------------------------------------------------------- */ -int stopStream() +int KernelAudio::stopStream() { try { system->stopStream(); return 1; } catch (RtAudioError &e) { - gLog("[KA] Stop stream error\n"); + gu_log("[KA] Stop stream error\n"); return 0; } } @@ -217,13 +215,13 @@ int stopStream() /* -------------------------------------------------------------------------- */ -string getDeviceName(unsigned dev) +string KernelAudio::getDeviceName(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).name; } catch (RtAudioError &e) { - gLog("[KA] invalid device ID = %d\n", dev); + gu_log("[KA] invalid device ID = %d\n", dev); return ""; } } @@ -232,7 +230,7 @@ string getDeviceName(unsigned dev) /* -------------------------------------------------------------------------- */ -int closeDevice() +int KernelAudio::closeDevice() { if (system->isStreamOpen()) { #if defined(__linux__) || defined(__APPLE__) @@ -242,7 +240,7 @@ int closeDevice() #endif system->closeStream(); delete system; - system = NULL; + system = nullptr; } return 1; } @@ -251,7 +249,7 @@ int closeDevice() /* -------------------------------------------------------------------------- */ -unsigned getMaxInChans(int dev) +unsigned KernelAudio::getMaxInChans(int dev) { if (dev == -1) return 0; @@ -259,7 +257,7 @@ unsigned getMaxInChans(int dev) return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).inputChannels; } catch (RtAudioError &e) { - gLog("[KA] Unable to get input channels\n"); + gu_log("[KA] Unable to get input channels\n"); return 0; } } @@ -268,13 +266,13 @@ unsigned getMaxInChans(int dev) /* -------------------------------------------------------------------------- */ -unsigned getMaxOutChans(unsigned dev) +unsigned KernelAudio::getMaxOutChans(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).outputChannels; } catch (RtAudioError &e) { - gLog("[KA] Unable to get output channels\n"); + gu_log("[KA] Unable to get output channels\n"); return 0; } } @@ -283,7 +281,7 @@ unsigned getMaxOutChans(unsigned dev) /* -------------------------------------------------------------------------- */ -bool isProbed(unsigned dev) +bool KernelAudio::isProbed(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).probed; @@ -297,7 +295,7 @@ bool isProbed(unsigned dev) /* -------------------------------------------------------------------------- */ -unsigned getDuplexChans(unsigned dev) +unsigned KernelAudio::getDuplexChans(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).duplexChannels; @@ -311,7 +309,7 @@ unsigned getDuplexChans(unsigned dev) /* -------------------------------------------------------------------------- */ -bool isDefaultIn(unsigned dev) +bool KernelAudio::isDefaultIn(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultInput; @@ -325,7 +323,7 @@ bool isDefaultIn(unsigned dev) /* -------------------------------------------------------------------------- */ -bool isDefaultOut(unsigned dev) +bool KernelAudio::isDefaultOut(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultOutput; @@ -339,7 +337,7 @@ bool isDefaultOut(unsigned dev) /* -------------------------------------------------------------------------- */ -int getTotalFreqs(unsigned dev) +int KernelAudio::getTotalFreqs(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.size(); @@ -353,7 +351,7 @@ int getTotalFreqs(unsigned dev) /* -------------------------------------------------------------------------- */ -int getFreq(unsigned dev, int i) +int KernelAudio::getFreq(unsigned dev, int i) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.at(i); @@ -367,12 +365,12 @@ int getFreq(unsigned dev, int i) /* -------------------------------------------------------------------------- */ -int getDefaultIn() +int KernelAudio::getDefaultIn() { return system->getDefaultInputDevice(); } -int getDefaultOut() +int KernelAudio::getDefaultOut() { return system->getDefaultOutputDevice(); } @@ -381,7 +379,7 @@ int getDefaultOut() /* -------------------------------------------------------------------------- */ -int getDeviceByName(const char *name) +int KernelAudio::getDeviceByName(const char *name) { for (unsigned i=0; i APIs; + vector APIs; RtAudio::getCompiledApi(APIs); for (unsigned i=0; i -#include -#include -jack_client_t *jackGetHandle() +int KernelAudio::jackSyncCb(jack_transport_state_t state, jack_position_t *pos, + void *arg) +{ + return G_KernelAudio.__jackSyncCb(state, pos, arg); +} + + +/* -------------------------------------------------------------------------- */ + + +jack_client_t *KernelAudio::jackGetHandle() { return (jack_client_t*) system->rtapi_->__HACK__getJackClient(); } -void jackStart() + +/* -------------------------------------------------------------------------- */ + + +void KernelAudio::jackStart() { if (api == SYS_API_JACK) { jack_client_t *client = jackGetHandle(); @@ -435,7 +444,10 @@ void jackStart() } -void jackStop() +/* -------------------------------------------------------------------------- */ + + +void KernelAudio::jackStop() { if (api == SYS_API_JACK) { jack_client_t *client = jackGetHandle(); @@ -444,42 +456,46 @@ void jackStop() } -void jackSetSyncCb() +/* -------------------------------------------------------------------------- */ + + +void KernelAudio::jackSetSyncCb() { jack_client_t *client = jackGetHandle(); - jack_set_sync_callback(client, jackSyncCb, NULL); + jack_set_sync_callback(client, jackSyncCb, nullptr); //jack_set_sync_timeout(client, 8); } -int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, +/* -------------------------------------------------------------------------- */ + + +int KernelAudio::__jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg) { switch (state) { case JackTransportStopped: - gLog("[KA] Jack transport stopped, frame=%d\n", pos->frame); + gu_log("[KA] Jack transport stopped, frame=%d\n", pos->frame); glue_stopSeq(false); // false = not from GUI if (pos->frame == 0) glue_rewindSeq(); break; case JackTransportRolling: - gLog("[KA] Jack transport rolling\n"); + gu_log("[KA] Jack transport rolling\n"); break; case JackTransportStarting: - gLog("[KA] Jack transport starting, frame=%d\n", pos->frame); + gu_log("[KA] Jack transport starting, frame=%d\n", pos->frame); glue_startSeq(false); // false = not from GUI if (pos->frame == 0) glue_rewindSeq(); break; default: - gLog("[KA] Jack transport [unknown]\n"); + gu_log("[KA] Jack transport [unknown]\n"); } return 1; } #endif - -} diff --git a/src/core/kernelAudio.h b/src/core/kernelAudio.h index 2ab1e12..ba3667e 100644 --- a/src/core/kernelAudio.h +++ b/src/core/kernelAudio.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelAudio * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef KERNELAUDIO_H @@ -32,26 +32,22 @@ #include "../deps/rtaudio-mod/RtAudio.h" -#if defined(__linux__) +#ifdef __linux__ #include #include #include #endif -using std::string; +class KernelAudio +{ +public: + KernelAudio(); -namespace kernelAudio { + int openDevice(int api, int outDev, int inDev, int outChan, int inChan, + int samplerate, int buffersize); - int openDevice( - int api, - int outDev, - int inDev, - int outChan, - int inChan, - int samplerate, - int buffersize); int closeDevice(); int startStream(); @@ -60,7 +56,7 @@ namespace kernelAudio { bool isProbed (unsigned dev); bool isDefaultIn (unsigned dev); bool isDefaultOut (unsigned dev); - string getDeviceName (unsigned dev); + std::string getDeviceName (unsigned dev); unsigned getMaxInChans (int dev); unsigned getMaxOutChans (unsigned dev); unsigned getDuplexChans (unsigned dev); @@ -70,29 +66,27 @@ namespace kernelAudio { int getDefaultOut (); int getDefaultIn (); bool hasAPI (int API); - string getRtAudioVersion(); + std::string getRtAudioVersion(); #ifdef __linux__ + jack_client_t *jackGetHandle(); void jackStart(); void jackStop(); void jackSetSyncCb(); - int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg); + static int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg); + int __jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg); + #endif - /* *** how to avoid multiple definition of *** - * When you declare a variable in a header file, every source file that - * includes that header, either directly or indirectly, gets its own - * separate copy of the variable. Then when you go to link all the .o - * files together, the linker sees that the variable is instantiated - * in a bunch of .o files. Make it extern in the header file and - * instantiate it in memory.cpp. */ - - extern RtAudio *system; - extern unsigned numDevs; - extern bool inputEnabled; - extern unsigned realBufsize; // reale bufsize from the soundcard - extern int api; -} + unsigned numDevs; + bool inputEnabled; + unsigned realBufsize; // reale bufsize from the soundcard + int api; + +private: + + RtAudio *system; +}; #endif diff --git a/src/core/kernelMidi.cpp b/src/core/kernelMidi.cpp index 36c99d9..9676143 100644 --- a/src/core/kernelMidi.cpp +++ b/src/core/kernelMidi.cpp @@ -27,44 +27,64 @@ * -------------------------------------------------------------------------- */ -#include +#include #include "../utils/log.h" -#include "../glue/glue.h" -#include "kernelMidi.h" +#include "../glue/channel.h" +#include "../glue/main.h" +#include "../glue/io.h" #include "mixer.h" +#include "const.h" #include "channel.h" #include "sampleChannel.h" +#include "midiChannel.h" #include "conf.h" #include "midiMapConf.h" +#include "pluginHost.h" +#include "kernelMidi.h" extern bool G_midiStatus; extern Conf G_Conf; extern Mixer G_Mixer; +extern KernelMidi G_KernelMidi; extern MidiMapConf G_MidiMap; +extern PluginHost G_PluginHost; using std::string; +using std::vector; + + +KernelMidi::KernelMidi() + : numOutPorts(0), + numInPorts (0), + api (0), // one api for both in & out + midiOut (nullptr), + midiIn (nullptr), + cb_learn (nullptr), + cb_data (nullptr) +{ +} -namespace kernelMidi +/* -------------------------------------------------------------------------- */ + + +void KernelMidi::callback(double t, vector *msg, void *data) { -int api = 0; // one api for both in & out -RtMidiOut *midiOut = NULL; -RtMidiIn *midiIn = NULL; -unsigned numOutPorts = 0; -unsigned numInPorts = 0; + G_KernelMidi.__callback(t, msg, data); +} + -cb_midiLearn *cb_learn = NULL; -void *cb_data = NULL; +/* -------------------------------------------------------------------------- */ -void __sendMidiLightningInitMsgs__() +void KernelMidi::sendMidiLightningInitMsgs() { for(unsigned i=0; igetPortCount(); - gLog("[KM] %d output MIDI ports found\n", numOutPorts); + gu_log("[KM] %d output MIDI ports found\n", numOutPorts); for (unsigned i=0; i 0) { try { midiOut->openPort(port, getOutPortName(port)); - gLog("[KM] MIDI out port %d open\n", port); + gu_log("[KM] MIDI out port %d open\n", port); /* TODO - it shold send midiLightning message only if there is a map loaded and available in G_MidiMap. */ - __sendMidiLightningInitMsgs__(); + sendMidiLightningInitMsgs(); return 1; } catch (RtMidiError &error) { - gLog("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str()); + gu_log("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str()); G_midiStatus = false; return 0; } @@ -150,14 +170,14 @@ int openOutDevice(int port) /* -------------------------------------------------------------------------- */ -int openInDevice(int port) +int KernelMidi::openInDevice(int port) { try { midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input"); G_midiStatus = true; } catch (RtMidiError &error) { - gLog("[KM] MIDI in device error: %s\n", error.getMessage().c_str()); + gu_log("[KM] MIDI in device error: %s\n", error.getMessage().c_str()); G_midiStatus = false; return 0; } @@ -165,9 +185,9 @@ int openInDevice(int port) /* print input ports */ numInPorts = midiIn->getPortCount(); - gLog("[KM] %d input MIDI ports found\n", numInPorts); + gu_log("[KM] %d input MIDI ports found\n", numInPorts); for (unsigned i=0; iopenPort(port, getInPortName(port)); midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now - gLog("[KM] MIDI in port %d open\n", port); + gu_log("[KM] MIDI in port %d open\n", port); midiIn->setCallback(&callback); return 1; } catch (RtMidiError &error) { - gLog("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str()); + gu_log("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str()); G_midiStatus = false; return 0; } @@ -193,9 +213,9 @@ int openInDevice(int port) /* -------------------------------------------------------------------------- */ -bool hasAPI(int API) +bool KernelMidi::hasAPI(int API) { - std::vector APIs; + vector APIs; RtMidi::getCompiledApi(APIs); for (unsigned i=0; igetPortName(p); } catch (RtMidiError &error) { return ""; } } -string getInPortName(unsigned p) +string KernelMidi::getInPortName(unsigned p) { try { return midiIn->getPortName(p); } catch (RtMidiError &error) { return ""; } @@ -223,29 +243,29 @@ string getInPortName(unsigned p) /* -------------------------------------------------------------------------- */ -void send(uint32_t data) +void KernelMidi::send(uint32_t data) { if (!G_midiStatus) return; - std::vector msg(1, getB1(data)); + 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]); + gu_log("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]); } /* -------------------------------------------------------------------------- */ -void send(int b1, int b2, int b3) +void KernelMidi::send(int b1, int b2, int b3) { if (!G_midiStatus) return; - std::vector msg(1, b1); + vector msg(1, b1); if (b2 != -1) msg.push_back(b2); @@ -253,23 +273,23 @@ void send(int b1, int b2, int b3) msg.push_back(b3); midiOut->sendMessage(&msg); - //gLog("[KM] send msg=(%X %X %X)\n", b1, b2, b3); + //gu_log("[KM] send msg=(%X %X %X)\n", b1, b2, b3); } /* -------------------------------------------------------------------------- */ -void callback(double t, std::vector *msg, void *data) +void KernelMidi::__callback(double t, vector *msg, void *data) { /* 0.8.0 - for now we handle other midi signals (common and real-time * messages) as unknown, for debugging purposes */ if (msg->size() < 3) { - gLog("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size()); + gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size()); for (unsigned i=0; isize(); i++) - gLog("%X", (int) msg->at(i)); - gLog("\n"); + gu_log("%X", (int) msg->at(i)); + gu_log("\n"); return; } @@ -282,104 +302,122 @@ void callback(double t, std::vector *msg, void *data) uint32_t value = input & 0x0000FF00; uint32_t pure = 0x00; if (!G_Conf.noNoteOff) - pure = input & 0xFFFF0000; // input without 'value' byte + pure = input & 0xFFFF0000; // input without 'value' byte else - pure = input & 0xFFFFFF00; // input with 'value' byte + pure = input & 0xFFFFFF00; // input with 'value' byte - gLog("[KM] MIDI received - 0x%X (chan %d)", input, chan >> 24); + gu_log("[KM] MIDI received - 0x%X (chan %d)\n", input, chan >> 24); /* start dispatcher. If midi learn is on don't parse channels, just * learn incoming midi signal. Otherwise process master events first, * then each channel in the stack. This way incoming signals don't * get processed by glue_* when midi learning is on. */ - if (cb_learn) { - gLog("\n"); + if (cb_learn) cb_learn(pure, cb_data); - } else { + processMaster(pure, value); + processChannels(pure, value); + } +} - /* process master events */ - if (pure == G_Conf.midiInRewind) { - gLog(" >>> rewind (global) (pure=0x%X)", pure); - glue_rewindSeq(); - } - else if (pure == G_Conf.midiInStartStop) { - gLog(" >>> startStop (global) (pure=0x%X)", pure); - glue_startStopSeq(); - } - else if (pure == G_Conf.midiInActionRec) { - gLog(" >>> actionRec (global) (pure=0x%X)", pure); - glue_startStopActionRec(); +/* -------------------------------------------------------------------------- */ + + +void KernelMidi::processMaster(uint32_t pure, uint32_t value) +{ + if (pure == G_Conf.midiInRewind) { + gu_log(" >>> rewind (master) (pure=0x%X)\n", pure); + glue_rewindSeq(); + } + else if (pure == G_Conf.midiInStartStop) { + gu_log(" >>> startStop (master) (pure=0x%X)\n", pure); + glue_startStopSeq(false); + } + else if (pure == G_Conf.midiInActionRec) { + gu_log(" >>> actionRec (master) (pure=0x%X)\n", pure); + glue_startStopActionRec(false); + } + else if (pure == G_Conf.midiInInputRec) { + gu_log(" >>> inputRec (master) (pure=0x%X)\n", pure); + glue_startStopInputRec(false); + } + else if (pure == G_Conf.midiInMetronome) { + gu_log(" >>> metronome (master) (pure=0x%X)\n", pure); + glue_startStopMetronome(false); + } + else if (pure == G_Conf.midiInVolumeIn) { + float vf = (value >> 8)/127.0f; + gu_log(" >>> input volume (master) (pure=0x%X, value=%d, float=%f)\n", + pure, value >> 8, vf); + glue_setInVol(vf, false); + } + else if (pure == G_Conf.midiInVolumeOut) { + float vf = (value >> 8)/127.0f; + gu_log(" >>> output volume (master) (pure=0x%X, value=%d, float=%f)\n", + pure, value >> 8, vf); + glue_setOutVol(vf, false); + } + else if (pure == G_Conf.midiInBeatDouble) { + gu_log(" >>> sequencer x2 (master) (pure=0x%X)\n", pure); + glue_beatsMultiply(); + } + else if (pure == G_Conf.midiInBeatHalf) { + gu_log(" >>> sequencer /2 (master) (pure=0x%X)\n", pure); + glue_beatsDivide(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void KernelMidi::processChannels(uint32_t pure, uint32_t value) +{ + for (unsigned i=0; imidiIn) + continue; + + if (pure == ch->midiInKeyPress) { + gu_log(" >>> keyPress, ch=%d (pure=0x%X)\n", ch->index, pure); + glue_keyPress(ch, false, false); } - else if (pure == G_Conf.midiInInputRec) { - gLog(" >>> inputRec (global) (pure=0x%X)", pure); - glue_startStopInputRec(false, false); // update gui, no popup messages + else if (pure == ch->midiInKeyRel) { + gu_log(" >>> keyRel ch=%d (pure=0x%X)\n", ch->index, pure); + glue_keyRelease(ch, false, false); } - else if (pure == G_Conf.midiInMetronome) { - gLog(" >>> metronome (global) (pure=0x%X)", pure); - glue_startStopMetronome(false); + else if (pure == ch->midiInMute) { + gu_log(" >>> mute ch=%d (pure=0x%X)\n", ch->index, pure); + glue_setMute(ch, false); } - else if (pure == G_Conf.midiInVolumeIn) { - float vf = (value >> 8)/127.0f; - gLog(" >>> input volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf); - glue_setInVol(vf, false); + else if (pure == ch->midiInSolo) { + gu_log(" >>> solo ch=%d (pure=0x%X)\n", ch->index, pure); + ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false); } - else if (pure == G_Conf.midiInVolumeOut) { + else if (pure == ch->midiInVolume) { float vf = (value >> 8)/127.0f; - gLog(" >>> output volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf); - glue_setOutVol(vf, false); + gu_log(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n", + ch->index, pure, value >> 8, vf); + glue_setChanVol(ch, vf, false); } - else if (pure == G_Conf.midiInBeatDouble) { - gLog(" >>> sequencer x2 (global) (pure=0x%X)", pure); - glue_beatsMultiply(); + else if (pure == ((SampleChannel*)ch)->midiInPitch) { + float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0] + gu_log(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n", + ch->index, pure, value >> 8, vf); + glue_setPitch(nullptr, (SampleChannel*)ch, vf, false); } - else if (pure == G_Conf.midiInBeatHalf) { - gLog(" >>> sequencer /2 (global) (pure=0x%X)", pure); - glue_beatsDivide(); + else if (pure == ((SampleChannel*)ch)->midiInReadActions) { + gu_log(" >>> start/stop read actions ch=%d (pure=0x%X)\n", ch->index, pure); + glue_startStopReadingRecs((SampleChannel*)ch, false); } - /* process channels */ - - for (unsigned i=0; imidiIn) continue; - - if (pure == ch->midiInKeyPress) { - gLog(" >>> keyPress, ch=%d (pure=0x%X)", ch->index, pure); - glue_keyPress(ch, false, false); - } - else if (pure == ch->midiInKeyRel) { - gLog(" >>> keyRel ch=%d (pure=0x%X)", ch->index, pure); - glue_keyRelease(ch, false, false); - } - else if (pure == ch->midiInMute) { - gLog(" >>> mute ch=%d (pure=0x%X)", ch->index, pure); - glue_setMute(ch, false); - } - else if (pure == ch->midiInSolo) { - gLog(" >>> solo ch=%d (pure=0x%X)", ch->index, pure); - ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false); - } - else if (pure == ch->midiInVolume) { - float vf = (value >> 8)/127.0f; - gLog(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf); - glue_setChanVol(ch, vf, false); - } - else if (pure == ((SampleChannel*)ch)->midiInPitch) { - float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0] - gLog(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf); - glue_setPitch(NULL, (SampleChannel*)ch, vf, false); - } - else if (pure == ((SampleChannel*)ch)->midiInReadActions) { - gLog(" >>> start/stop read actions ch=%d (pure=0x%X)", ch->index, pure); - glue_startStopReadingRecs((SampleChannel*)ch, false); - } - } - gLog("\n"); + /* redirect full midi message to plugins */ + + ch->receiveMidi(pure | value); } } @@ -387,13 +425,7 @@ void callback(double t, std::vector *msg, void *data) /* -------------------------------------------------------------------------- */ -std::string getRtMidiVersion() +string KernelMidi::getRtMidiVersion() { return midiOut->getVersion(); } - - -/* -------------------------------------------------------------------------- */ - - -} // namespace diff --git a/src/core/kernelMidi.h b/src/core/kernelMidi.h index 161a953..834e0de 100644 --- a/src/core/kernelMidi.h +++ b/src/core/kernelMidi.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelMidi * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,45 +24,41 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef KERNELMIDI_H #define KERNELMIDI_H -#include -#include -#include "channel.h" - +#ifdef __APPLE__ // our compiler still doesn't know about cstdint (c++11 stuff) + #include +#else + #include +#endif +#include +#include -using std::string; +class KernelMidi +{ +public: -namespace kernelMidi { + unsigned numOutPorts; + unsigned numInPorts; - extern int api; // one api for both in & out - extern unsigned numOutPorts; - extern unsigned numInPorts; + KernelMidi(); typedef void (cb_midiLearn) (uint32_t, void *); - /* cb_learn - * callback prepared by the gdMidiGrabber window and called by - * kernelMidi. It contains things to do once the midi message has been - * stored. */ - - extern cb_midiLearn *cb_learn; - extern void *cb_data; - void startMidiLearn(cb_midiLearn *cb, void *data); void stopMidiLearn(); - inline int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; } - inline int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; } - inline int getB3(uint32_t iValue) { return (iValue >> 8) & 0xFF; } + int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; } + int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; } + int getB3(uint32_t iValue) { return (iValue >> 8) & 0xFF; } - inline uint32_t getIValue(int b1, int b2, int b3) { + uint32_t getIValue(int b1, int b2, int b3) { return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00); } @@ -91,17 +87,38 @@ namespace kernelMidi { /* getIn/OutPortName * return the name of the port 'p'. */ - string getInPortName(unsigned p); - string getOutPortName(unsigned p); + std::string getInPortName(unsigned p); + std::string getOutPortName(unsigned p); bool hasAPI(int API); + std::string getRtMidiVersion(); + +private: + + int api; + class RtMidiOut *midiOut; + class RtMidiIn *midiIn; + + /* cb_learn + * callback prepared by the gdMidiGrabber window and called by + * kernelMidi. It contains things to do once the midi message has been + * stored. */ + + cb_midiLearn *cb_learn; + void *cb_data; + /* callback * master callback for input events. */ - void callback(double t, std::vector *msg, void *data); + static void callback(double t, std::vector *msg, void *data); + void __callback(double t, std::vector *msg, void *data); + + void sendMidiLightningInitMsgs(); + - string getRtMidiVersion(); -} + void processMaster(uint32_t pure, uint32_t value); + void processChannels(uint32_t pure, uint32_t value); +}; #endif diff --git a/src/core/midiChannel.cpp b/src/core/midiChannel.cpp index 3dd0cef..cf1f88a 100644 --- a/src/core/midiChannel.cpp +++ b/src/core/midiChannel.cpp @@ -34,17 +34,21 @@ #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" +#include "mixer.h" #include "kernelMidi.h" +extern Recorder G_Recorder; +extern KernelMidi G_KernelMidi; +extern PluginHost G_PluginHost; +extern Mixer G_Mixer; + + MidiChannel::MidiChannel(int bufferSize, MidiMapConf *midiMapConf) : Channel (CHANNEL_MIDI, STATUS_OFF, bufferSize, midiMapConf), midiOut (false), midiOutChan(MIDI_CHANS[0]) { -#ifdef WITH_VST // init VstEvents stack - freeVstMidiEvents(true); -#endif } @@ -69,28 +73,14 @@ void MidiChannel::copy(const Channel *_src, pthread_mutex_t *pluginMutex) /* -------------------------------------------------------------------------- */ -#ifdef WITH_VST - -void MidiChannel::freeVstMidiEvents(bool init) -{ - midiBuffer.clear(); -} - -#endif - - -/* -------------------------------------------------------------------------- */ - - #ifdef WITH_VST void MidiChannel::addVstMidiEvent(uint32_t msg, int localFrame) { juce::MidiMessage message = juce::MidiMessage( - kernelMidi::getB1(msg), - kernelMidi::getB2(msg), - kernelMidi::getB3(msg)); - + G_KernelMidi.getB1(msg), + G_KernelMidi.getB2(msg), + G_KernelMidi.getB3(msg)); midiBuffer.addEvent(message, localFrame); } @@ -124,7 +114,7 @@ void MidiChannel::quantize(int index, int localFrame, int globalFrame) {} /* -------------------------------------------------------------------------- */ -void MidiChannel::parseAction(recorder::action *a, int localFrame, +void MidiChannel::parseAction(Recorder::action *a, int localFrame, int globalFrame, int quantize, bool mixerIsRunning) { if (a->type == ACTION_MIDI) @@ -156,7 +146,7 @@ void MidiChannel::setMute(bool internal) { mute = true; // internal mute does not exist for midi (for now) if (midiOut) - kernelMidi::send(MIDI_ALL_NOTES_OFF); + G_KernelMidi.send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0); #endif @@ -177,16 +167,16 @@ void MidiChannel::unsetMute(bool internal) /* -------------------------------------------------------------------------- */ -void MidiChannel::process(float *buffer) +void MidiChannel::process(float *outBuffer, float *inBuffer) { #ifdef WITH_VST pluginHost->processStack(vChan, PluginHost::CHANNEL, this); - freeVstMidiEvents(); #endif + /* TODO - isn't this useful only if WITH_VST ? */ for (int j=0; jiValue | MIDI_CHANS[midiOutChan]); + G_KernelMidi.send(a->iValue | MIDI_CHANS[midiOutChan]); #ifdef WITH_VST addVstMidiEvent(a->iValue, localFrame); @@ -302,7 +292,7 @@ void MidiChannel::sendMidi(uint32_t data) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { if (midiOut) - kernelMidi::send(data | MIDI_CHANS[midiOutChan]); + G_KernelMidi.send(data | MIDI_CHANS[midiOutChan]); #ifdef WITH_VST addVstMidiEvent(data, 0); #endif @@ -316,7 +306,7 @@ void MidiChannel::sendMidi(uint32_t data) void MidiChannel::rewind() { if (midiOut) - kernelMidi::send(MIDI_ALL_NOTES_OFF); + G_KernelMidi.send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0); #endif @@ -336,3 +326,41 @@ int MidiChannel::writePatch(int i, bool isProject, Patch *patch) return 0; } + + +/* -------------------------------------------------------------------------- */ + + +void MidiChannel::receiveMidi(uint32_t msg) +{ + if (!armed) + return; + while (true) { + if (pthread_mutex_trylock(&G_PluginHost.mutex_midi) != 0) + continue; + gu_log("[Channel::processMidi] msg=%X\n", msg); +#ifdef WITH_VST + addVstMidiEvent(msg, 0); +#endif + pthread_mutex_unlock(&G_PluginHost.mutex_midi); + break; + } + + if (G_Recorder.canRec(this)) + G_Recorder.rec(index, ACTION_MIDI, G_Mixer.actualFrame, msg); +} + + +/* -------------------------------------------------------------------------- */ + + +bool MidiChannel::canInputRec() +{ + return false; // midi channels don't handle input audio +} + + +/* -------------------------------------------------------------------------- */ + + +void MidiChannel::clear() {} diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h index 011ae2f..dcaaa27 100644 --- a/src/core/midiChannel.h +++ b/src/core/midiChannel.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef MIDI_CHANNEL_H @@ -48,43 +48,41 @@ public: bool midiOut; // enable midi output uint8_t midiOutChan; // midi output channel - void copy(const Channel *src, pthread_mutex_t *pluginMutex); - - void process (float *buffer); - void start (int frame, bool doQuantize, int quantize, bool mixerIsRunning); - void kill (int frame); - void empty (); - void stopBySeq (bool chansStopOnSeqHalt); - void stop (); - void rewind (); - void setMute (bool internal); - void unsetMute (bool internal); - int readPatch_DEPR_ (const char *file, int i, class Patch_DEPR_ *patch, - int samplerate, int rsmpQuality); - int readPatch (const string &basePath, int i, class Patch *patch, - pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality); - int writePatch (int i, bool isProject, class Patch *patch); - void quantize (int index, int localFrame, int globalFrame); - void onZero (int frame, bool recsStopOnChanHalt); - void onBar (int frame); - void parseAction(recorder::action *a, int localFrame, int globalFrame, - int quantize, bool mixerIsRunning); - - /* ---------------------------------------------------------------- */ + void copy(const Channel *src, pthread_mutex_t *pluginMutex) override; + void clear() override; + void process(float *outBuffer, float *inBuffer) override; + void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning, + bool forceStart, bool isUserGenerated) override; + void kill(int frame) override; + void empty() override; + void stopBySeq(bool chansStopOnSeqHalt) override; + void stop() override; + void rewind() override; + void setMute(bool internal) override; + void unsetMute(bool internal) override; + int readPatch_DEPR_(const char *file, int i, class Patch_DEPR_ *patch, + int samplerate, int rsmpQuality) override; + int readPatch(const string &basePath, int i, class Patch *patch, + pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override; + int writePatch(int i, bool isProject, class Patch *patch) override; + void quantize(int index, int localFrame, int globalFrame) override; + void onZero(int frame, bool recsStopOnChanHalt) override; + void onBar(int frame) override; + void parseAction(Recorder::action *a, int localFrame, int globalFrame, + int quantize, bool mixerIsRunning) override; + void receiveMidi(uint32_t msg) override; + bool canInputRec() override; + + /* ------------------------------------------------------------------------ */ /* sendMidi * send Midi event to the outside world. */ - void sendMidi(recorder::action *a, int localFrame); + void sendMidi(Recorder::action *a, int localFrame); void sendMidi(uint32_t data); -#ifdef WITH_VST - - /* freeVstMidiEvents - * empty vstEvents structure. Init: use the method for channel - * initialization. */ - void freeVstMidiEvents(bool init=false); +#ifdef WITH_VST /* addVstMidiEvent * Add a new Midi event to the midiEvent stack fom a composite uint32_t raw diff --git a/src/core/midiMapConf.cpp b/src/core/midiMapConf.cpp index 41d3706..c2b40eb 100644 --- a/src/core/midiMapConf.cpp +++ b/src/core/midiMapConf.cpp @@ -35,7 +35,7 @@ #include #include "midiMapConf.h" #include "const.h" -#include "../utils/utils.h" +#include "../utils/string.h" #include "../utils/log.h" @@ -46,18 +46,18 @@ using std::vector; void MidiMapConf::init() { - midimapsPath = gGetHomePath() + G_SLASH + "midimaps" + G_SLASH; + midimapsPath = gu_getHomePath() + G_SLASH + "midimaps" + G_SLASH; /* scan dir of midi maps and load the filenames into <>maps. */ - gLog("[MidiMapConf::init] scanning midimaps directory...\n"); + gu_log("[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"); + gu_log("[MidiMapConf::init] unable to scan midimaps directory!\n"); return; } @@ -67,12 +67,12 @@ void MidiMapConf::init() // TODO - check if is a valid midimap file (verify headers) - gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name); + gu_log("[MidiMapConf::init] found midimap '%s'\n", ep->d_name); maps.push_back(ep->d_name); } - gLog("[MidiMapConf::init] total midimaps found: %d\n", maps.size()); + gu_log("[MidiMapConf::init] total midimaps found: %d\n", maps.size()); closedir(dp); } @@ -125,16 +125,16 @@ void MidiMapConf::setDefault() int MidiMapConf::read(const string &file) { if (file.empty()) { - gLog("[MidiMapConf::read] midimap not specified, nothing to do\n"); + gu_log("[MidiMapConf::read] midimap not specified, nothing to do\n"); return MIDIMAP_NOT_SPECIFIED; } - gLog("[MidiMapConf::read] reading midimap file '%s'\n", file.c_str()); + gu_log("[MidiMapConf::read] reading midimap file '%s'\n", file.c_str()); string path = midimapsPath + file; jRoot = json_load_file(path.c_str(), 0, &jError); if (!jRoot) { - gLog("[MidiMapConf::read] unreadable midimap file. Error on line %d: %s\n", jError.line, jError.text); + gu_log("[MidiMapConf::read] unreadable midimap file. Error on line %d: %s\n", jError.line, jError.text); return MIDIMAP_UNREADABLE; } @@ -178,7 +178,7 @@ bool MidiMapConf::readInitCommands(json_t *jContainer) json_t *jInitCommand; json_array_foreach(jInitCommands, commandIndex, jInitCommand) { - string indexStr = "init command " + gItoa(commandIndex); + string indexStr = "init command " + gu_itoa(commandIndex); if (!checkObject(jInitCommand, indexStr.c_str())) return 0; @@ -238,7 +238,7 @@ void MidiMapConf::parse(message_t *message) message->value = strtoul(output.c_str(), NULL, 16); - gLog("[MidiMapConf::parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n", + gu_log("[MidiMapConf::parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n", message->channel, message->valueStr.c_str(), message->value, message->offset); } @@ -296,16 +296,16 @@ void MidiMapConf::setDefault_DEPR_() int MidiMapConf::readMap_DEPR_(string file) { if (file.empty()) { - gLog("[MidiMapConf::readMap_DEPR_] midimap not specified, nothing to do\n"); + gu_log("[MidiMapConf::readMap_DEPR_] midimap not specified, nothing to do\n"); return MIDIMAP_NOT_SPECIFIED; } - gLog("[MidiMapConf::readMap_DEPR_] reading midimap file '%s'\n", file.c_str()); + gu_log("[MidiMapConf::readMap_DEPR_] reading midimap file '%s'\n", file.c_str()); string path = midimapsPath + file; fp = fopen(path.c_str(), "r"); if (!fp) { - gLog("[MidiMapConf::readMap_DEPR_] unreadable midimap file\n"); + gu_log("[MidiMapConf::readMap_DEPR_] unreadable midimap file\n"); return MIDIMAP_UNREADABLE; } @@ -313,20 +313,20 @@ int MidiMapConf::readMap_DEPR_(string file) device = getValue("device"); if (brand.empty() || device.empty()) { - gLog("[MidiMapConf::readMap_DEPR_] invalid midimap file\n"); + gu_log("[MidiMapConf::readMap_DEPR_] invalid midimap file\n"); return MIDIMAP_INVALID; } - gLog("[MidiMapConf::readMap_DEPR_] reading midimap for %s %s\n", + gu_log("[MidiMapConf::readMap_DEPR_] reading midimap for %s %s\n", brand.c_str(), device.c_str()); /* parse init commands */ vector ic; - gSplit(getValue("init_commands"), ";", &ic); + gu_split(getValue("init_commands"), ";", &ic); for (unsigned i=0; i<(unsigned)MAX_INIT_COMMANDS && i #include "dataStorageIni.h" #include "dataStorageJson.h" -#include "../utils/utils.h" +#include "../utils/fs.h" #if defined(__APPLE__) #include #endif diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index 5ca38cd..7321f1b 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -27,11 +27,7 @@ * -------------------------------------------------------------------------- */ -#include #include "../utils/log.h" -#include "../utils/gui_utils.h" -#include "mixer.h" -#include "init.h" #include "wave.h" #include "recorder.h" #include "pluginHost.h" @@ -42,9 +38,13 @@ #include "sampleChannel.h" #include "midiChannel.h" #include "kernelMidi.h" +#include "mixer.h" +extern KernelAudio G_KernelAudio; extern Mixer G_Mixer; +extern Recorder G_Recorder; +extern KernelMidi G_KernelMidi; extern MidiMapConf G_MidiMap; extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; @@ -62,12 +62,6 @@ Mixer::Mixer() /* -------------------------------------------------------------------------- */ -Mixer::~Mixer() {} - - -/* -------------------------------------------------------------------------- */ - - #define TICKSIZE 38 @@ -102,6 +96,7 @@ void Mixer::init() docross = false; rewindWait = false; running = false; + recording = false; ready = true; waitRec = 0; actualFrame = 0; @@ -120,7 +115,6 @@ void Mixer::init() inVol = DEFAULT_IN_VOL; peakOut = 0.0f; peakIn = 0.0f; - chanInput = NULL; inputTracker = 0; actualBeat = 0; @@ -137,7 +131,7 @@ void Mixer::init() /** TODO - set kernelAudio::realBufsize * 2 as private member */ vChanInput = NULL; - vChanInToOut = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float)); + vChanInToOut = (float *) malloc(G_KernelAudio.realBufsize * 2 * sizeof(float)); pthread_mutex_init(&mutex_recs, NULL); pthread_mutex_init(&mutex_chans, NULL); @@ -154,7 +148,7 @@ void Mixer::init() Channel *Mixer::addChannel(int type) { Channel *ch; - int bufferSize = kernelAudio::realBufsize*2; + int bufferSize = G_KernelAudio.realBufsize * 2; if (type == CHANNEL_SAMPLE) ch = new SampleChannel(bufferSize, &G_MidiMap); @@ -175,7 +169,7 @@ Channel *Mixer::addChannel(int type) } ch->index = getNewIndex(); - gLog("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size()); + gu_log("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size()); return ch; } @@ -214,7 +208,7 @@ int Mixer::deleteChannel(Channel *ch) } if (index == -1) { - gLog("[Mixer::deleteChannel] unable to find Channel %d for deletion!\n", ch->index); + gu_log("[Mixer::deleteChannel] unable to find Channel %d for deletion!\n", ch->index); return 0; } @@ -228,7 +222,7 @@ int Mixer::deleteChannel(Channel *ch) return 1; } //else - // gLog("[mixer::deleteChannel] waiting for mutex...\n"); + // gu_log("[mixer::deleteChannel] waiting for mutex...\n"); } } @@ -241,7 +235,7 @@ Channel *Mixer::getChannelByIndex(int index) for (unsigned i=0; iindex == index) return channels.at(i); - gLog("[mixer::getChannelByIndex] channel at index %d not found!\n", index); + gu_log("[mixer::getChannelByIndex] channel at index %d not found!\n", index); return NULL; } @@ -253,7 +247,7 @@ void Mixer::sendMIDIsync() { if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { if (actualFrame % (framesPerBeat/24) == 0) - kernelMidi::send(MIDI_CLOCK, -1, -1); + G_KernelMidi.send(MIDI_CLOCK, -1, -1); } else if (G_Conf.midiSync == MIDI_SYNC_MTC_M) { @@ -271,10 +265,10 @@ void Mixer::sendMIDIsync() * seconds high nibble */ if (midiTCframes % 2 == 0) { - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F) | 0x00, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4) | 0x10, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4) | 0x30, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F) | 0x00, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCframes >> 4) | 0x10, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCseconds >> 4) | 0x30, -1); } /* minutes low nibble @@ -283,10 +277,10 @@ void Mixer::sendMIDIsync() * hours high nibble SMPTE frame rate */ else { - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4) | 0x50, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F) | 0x60, -1); - kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4) | 0x70, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTCminutes >> 4) | 0x50, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTChours & 0x0F) | 0x60, -1); + G_KernelMidi.send(MIDI_MTC_QUARTER, (midiTChours >> 4) | 0x70, -1); } midiTCframes++; @@ -305,7 +299,7 @@ void Mixer::sendMIDIsync() midiTCminutes = 0; } } - //gLog("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes); + //gu_log("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes); } } } @@ -328,250 +322,64 @@ void Mixer::sendMIDIrewind() * SMPTE time in one message */ if (G_Conf.midiSync == MIDI_SYNC_MTC_M) { - kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00); // send msg on channel 0 - kernelMidi::send(0x01, 0x01, 0x00); // hours 0 - kernelMidi::send(0x00, 0x00, 0x00); // mins, secs, frames 0 - kernelMidi::send(MIDI_EOX, -1, -1); // end of sysex + G_KernelMidi.send(MIDI_SYSEX, 0x7F, 0x00); // send msg on channel 0 + G_KernelMidi.send(0x01, 0x01, 0x00); // hours 0 + G_KernelMidi.send(0x00, 0x00, 0x00); // mins, secs, frames 0 + G_KernelMidi.send(MIDI_EOX, -1, -1); // end of sysex } } /* -------------------------------------------------------------------------- */ -int Mixer::masterPlay( - void *out_buf, void *in_buf, unsigned n_frames, +int Mixer::masterPlay(void *outBuf, void *inBuf, unsigned bufferSize, double streamTime, RtAudioStreamStatus status, void *userData) { - return G_Mixer.__masterPlay(out_buf, in_buf, n_frames); + return G_Mixer.__masterPlay(outBuf, inBuf, bufferSize); } /* -------------------------------------------------------------------------- */ -int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) +int Mixer::__masterPlay(void *_outBuf, void *_inBuf, unsigned bufferSize) { if (!ready) return 0; - float *outBuf = ((float *) out_buf); - float *inBuf = ((float *) in_buf); - bufferFrames *= 2; // stereo + float *outBuf = (float *) _outBuf; + float *inBuf = G_KernelAudio.inputEnabled ? (float *) _inBuf : nullptr; + bufferSize *= 2; // stereo peakOut = 0.0f; // reset peak calculator peakIn = 0.0f; // reset peak calculator - /* always clean each buffer */ - - memset(outBuf, 0, sizeof(float) * bufferFrames); // out - memset(vChanInToOut, 0, sizeof(float) * bufferFrames); // inToOut vChan - - pthread_mutex_lock(&mutex_chans); - for (unsigned i=0; itype == CHANNEL_SAMPLE) - ((SampleChannel*)channels.at(i))->clear(); - pthread_mutex_unlock(&mutex_chans); - - for (unsigned j=0; j peakIn) - peakIn = inBuf[j] * inVol; - - /* "hear what you're playing" - process, copy and paste the input buffer - * onto the output buffer */ - - if (inToOut) { - vChanInToOut[j] = inBuf[j] * inVol; - vChanInToOut[j+1] = inBuf[j+1] * inVol; - } - } - - /* operations to do if the sequencer is running: - * - compute quantizer - * - time check for LOOP_REPEAT - * - reset loops at beat 0 - * - read recorded actions - * - reset actualFrame */ + clearAllBuffers(outBuf, bufferSize); + for (unsigned j=0; j= totalFrames) - inputTracker = 0; - } - } - - /* quantizer computations: quantize rewind and all channels. */ - - if (quantize > 0 && quanto > 0) { - if (actualFrame % (quanto) == 0) { // is quanto! - if (rewindWait) { - rewindWait = false; - rewind(); - } - pthread_mutex_lock(&mutex_chans); - for (unsigned k=0; kquantize(k, j, actualFrame); // j == localFrame - pthread_mutex_unlock(&mutex_chans); - } - } - - /* reset LOOP_REPEAT, if a bar has passed */ - - if (actualFrame % framesPerBar == 0 && actualFrame != 0) { - if (metronome) - tickPlay = true; - - pthread_mutex_lock(&mutex_chans); - for (unsigned k=0; konBar(j); - pthread_mutex_unlock(&mutex_chans); - } - - /* reset loops on beat 0 */ - - if (actualFrame == 0) { - pthread_mutex_lock(&mutex_chans); - for (unsigned k=0; konZero(j, G_Conf.recsStopOnChanHalt); - pthread_mutex_unlock(&mutex_chans); - } - - /* reading all actions recorded */ - - pthread_mutex_lock(&mutex_recs); - for (unsigned y=0; ychan; - Channel *ch = getChannelByIndex(index); - ch->parseAction(recorder::global.at(y).at(z), j, actualFrame, quantize, running); - } - break; - } - } - pthread_mutex_unlock(&mutex_recs); - - /* increase actualFrame */ - + lineInRec(inBuf, j); + doQuantize(j); + testBar(j); + testFirstBeat(j); + readActions(j); actualFrame += 2; - - /* if actualFrame > totalFrames the sequencer returns to frame 0, - * beat 0. This must be the last operation. */ - - if (actualFrame > totalFrames) { - actualFrame = 0; - actualBeat = 0; - } - else - if (actualFrame % framesPerBeat == 0 && actualFrame > 0) { - actualBeat++; - - /* avoid tick and tock to overlap when a new bar has passed (which - * is also a beat) */ - - if (metronome && !tickPlay) - tockPlay = true; - } - + testLastBeat(); // this test must be the last one sendMIDIsync(); - - } // if (running) - - /* sum channels, CHANNEL_SAMPLE only */ - - pthread_mutex_lock(&mutex_chans); - for (unsigned k=0; ktype == CHANNEL_SAMPLE) - ((SampleChannel*)channels.at(k))->sum(j, running); } - pthread_mutex_unlock(&mutex_chans); - - /* metronome play */ - /** FIXME - move this one after the peak meter calculation */ - - if (tockPlay) { - outBuf[j] += tock[tockTracker]; - outBuf[j+1] += tock[tockTracker]; - tockTracker++; - if (tockTracker >= TICKSIZE-1) { - tockPlay = false; - tockTracker = 0; - } - } - if (tickPlay) { - outBuf[j] += tick[tickTracker]; - outBuf[j+1] += tick[tickTracker]; - tickTracker++; - if (tickTracker >= TICKSIZE-1) { - tickPlay = false; - tickTracker = 0; - } - } - } // end loop J - - - /* final loop: sum virtual channels and process plugins. */ - - pthread_mutex_lock(&mutex_chans); - for (unsigned k=0; kprocess(outBuf); - pthread_mutex_unlock(&mutex_chans); - - /* processing fxs master in & out, if any. */ - -#ifdef WITH_VST - pthread_mutex_lock(&mutex_plugins); - G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT); - G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN); - pthread_mutex_unlock(&mutex_plugins); -#endif - - /* post processing master fx + peak calculation. */ - - for (unsigned j=0; j peakOut) - peakOut = outBuf[j]; + renderIO(outBuf, inBuf); - if (G_Conf.limitOutput) { - if (outBuf[j] > 1.0f) - outBuf[j] = 1.0f; - else if (outBuf[j] < -1.0f) - outBuf[j] = -1.0f; + /* post processing */ - if (outBuf[j+1] > 1.0f) - outBuf[j+1] = 1.0f; - else if (outBuf[j+1] < -1.0f) - outBuf[j+1] = -1.0f; - } + for (unsigned j=0; jtype == CHANNEL_MIDI) + continue; + SampleChannel *ch = (SampleChannel*) channels.at(i); + if (ch->armed) + memcpy(ch->wave->data, vChanInput, totalFrames * sizeof(float)); + } + memset(vChanInput, 0, totalFrames * sizeof(float)); // clear vchan +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::lineInRec(float *inBuf, unsigned frame) +{ + if (!mh_hasArmedSampleChannels() || !G_KernelAudio.inputEnabled || !recording) + return; + + /* Delay comp: wait until waitRec reaches delayComp. WaitRec + * returns to 0 in mixerHandler, as soon as the recording ends */ + + if (waitRec < G_Conf.delayComp) { + waitRec += 2; + return; + } + + vChanInput[inputTracker] += inBuf[frame] * inVol; + vChanInput[inputTracker+1] += inBuf[frame+1] * inVol; + inputTracker += 2; + if (inputTracker >= totalFrames) + inputTracker = 0; +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::processLineIn(float *inBuf, unsigned frame) +{ + if (!G_KernelAudio.inputEnabled) + return; + + /* input peak calculation (left chan only so far). */ + + if (inBuf[frame] * inVol > peakIn) + peakIn = inBuf[frame] * inVol; + + /* "hear what you're playing" - process, copy and paste the input buffer + * onto the output buffer */ + + if (inToOut) { + vChanInToOut[frame] = inBuf[frame] * inVol; + vChanInToOut[frame+1] = inBuf[frame+1] * inVol; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::readActions(unsigned frame) +{ + pthread_mutex_lock(&mutex_recs); + for (unsigned i=0; ichan; + Channel *ch = getChannelByIndex(index); + ch->parseAction(G_Recorder.global.at(i).at(j), frame, actualFrame, quantize, running); + } + break; + } } - else { + pthread_mutex_unlock(&mutex_recs); +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::doQuantize(unsigned frame) +{ + if (quantize < 0 || quanto <= 0) // if quantizer disabled + return; + if (actualFrame % (quanto) != 0) // if a quanto has not passed yet + return; + + if (rewindWait) { + rewindWait = false; + rewind(); + } + pthread_mutex_lock(&mutex_chans); + for (unsigned i=0; iquantize(i, frame, actualFrame); // j == localFrame + pthread_mutex_unlock(&mutex_chans); +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::testBar(unsigned frame) +{ + if (actualFrame % framesPerBar != 0 || actualFrame == 0) + return; + + if (metronome) + tickPlay = true; + + pthread_mutex_lock(&mutex_chans); + for (unsigned k=0; konBar(frame); + pthread_mutex_unlock(&mutex_chans); +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::testFirstBeat(unsigned frame) +{ + if (actualFrame != 0) + return; + pthread_mutex_lock(&mutex_chans); + for (unsigned k=0; konZero(frame, G_Conf.recsStopOnChanHalt); + pthread_mutex_unlock(&mutex_chans); +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::testLastBeat() +{ + /* if actualFrame > totalFrames the sequencer returns to frame 0, + * beat 0. This must be the last operation. */ + + if (actualFrame > totalFrames) { + actualFrame = 0; + actualBeat = 0; + } + else + if (actualFrame % framesPerBeat == 0 && actualFrame > 0) { + actualBeat++; + + /* avoid tick and tock to overlap when a new bar has passed (which + * is also a beat) */ + + if (metronome && !tickPlay) + tockPlay = true; + } +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::sumChannels(unsigned frame) +{ + pthread_mutex_lock(&mutex_chans); + for (unsigned k=0; ktype == CHANNEL_SAMPLE) + ((SampleChannel*)channels.at(k))->sum(frame, running); + } + pthread_mutex_unlock(&mutex_chans); +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::renderMetronome(float *outBuf, unsigned frame) +{ + if (tockPlay) { + outBuf[frame] += tock[tockTracker]; + outBuf[frame+1] += tock[tockTracker]; + tockTracker++; + if (tockTracker >= TICKSIZE-1) { + tockPlay = false; + tockTracker = 0; + } + } + if (tickPlay) { + outBuf[frame] += tick[tickTracker]; + outBuf[frame+1] += tick[tickTracker]; + tickTracker++; + if (tickTracker >= TICKSIZE-1) { + tickPlay = false; + tickTracker = 0; + } + } +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::renderIO(float *outBuf, float *inBuf) +{ + pthread_mutex_lock(&mutex_chans); + for (unsigned k=0; kprocess(outBuf, inBuf); + pthread_mutex_unlock(&mutex_chans); + #ifdef WITH_VST - G_PluginHost.processStackOffline(vChanInput, PluginHost::MASTER_IN, 0, totalFrames); + pthread_mutex_lock(&mutex_plugins); + G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT); + G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN); + pthread_mutex_unlock(&mutex_plugins); #endif - int numFrames = totalFrames*sizeof(float); - memcpy(chanInput->wave->data, vChanInput, numFrames); - memset(vChanInput, 0, numFrames); // clear vchan - return true; +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::computePeak(float *outBuf, unsigned frame) +{ + /* TODO it takes into account only left channel so far! */ + if (outBuf[frame] > peakOut) + peakOut = outBuf[frame]; +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::limitOutput(float *outBuf, unsigned frame) +{ + if (outBuf[frame] > 1.0f) + outBuf[frame] = 1.0f; + else + if (outBuf[frame] < -1.0f) + outBuf[frame] = -1.0f; + + if (outBuf[frame+1] > 1.0f) + outBuf[frame+1] = 1.0f; + else + if (outBuf[frame+1] < -1.0f) + outBuf[frame+1] = -1.0f; +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::finalizeOutput(float *outBuf, unsigned frame) +{ + /* merge vChanInToOut, if enabled */ + + if (inToOut) { + outBuf[frame] += vChanInToOut[frame]; + outBuf[frame+1] += vChanInToOut[frame+1]; } + outBuf[frame] *= outVol; + outBuf[frame+1] *= outVol; +} + + +/* -------------------------------------------------------------------------- */ + + +void Mixer::clearAllBuffers(float *outBuf, unsigned bufferSize) +{ + memset(outBuf, 0, sizeof(float) * bufferSize); // out + memset(vChanInToOut, 0, sizeof(float) * bufferSize); // inToOut vChan + + pthread_mutex_lock(&mutex_chans); + for (unsigned i=0; iclear(); + pthread_mutex_unlock(&mutex_chans); } diff --git a/src/core/mixer.h b/src/core/mixer.h index 8387efd..f8afb46 100644 --- a/src/core/mixer.h +++ b/src/core/mixer.h @@ -30,15 +30,10 @@ #ifndef MIXER_H #define MIXER_H -#include + #include #include -#include "const.h" #include "kernelAudio.h" -#include "../utils/utils.h" - - -using std::vector; class Mixer @@ -46,7 +41,6 @@ class Mixer public: Mixer(); - ~Mixer(); void init(); int close(); @@ -64,11 +58,9 @@ public: /* masterPlay * core method (callback) */ - static int masterPlay( - void *out_buf, void *in_buf, unsigned n_frames, - double streamTime, RtAudioStreamStatus status, void *userData - ); - int __masterPlay(void *out_buf, void *in_buf, unsigned n_frames); + static int masterPlay(void *outBuf, void *inBuf, unsigned bufferSize, + double streamTime, RtAudioStreamStatus status, void *userData); + int __masterPlay(void *outBuf, void *inBuf, unsigned bufferSize); /* updateFrameBars * updates bpm, frames, beats and so on. */ @@ -104,7 +96,7 @@ public: * memcpy the virtual channel input in the channel designed for input * recording. Called by mixerHandler on stopInputRec() */ - bool mergeVirtualInput(); + void mergeVirtualInput(); /* getChannelByIndex * return channel with given index 'i'. */ @@ -131,9 +123,10 @@ public: XFADE = 0x02 }; - vector channels; + std::vector channels; bool running; + bool recording; // is recording something? bool ready; float *vChanInput; // virtual channel for recording float *vChanInToOut; // virtual channel in->out bridge (hear what you're playin) @@ -166,11 +159,6 @@ public: int tickTracker, tockTracker; bool tickPlay, tockPlay; // 1 = play, 0 = stop - /* chanInput - * the active channel during a recording. NULL = no channels active */ - - class SampleChannel *chanInput; - /* inputTracker * position of the sample in the input side (recording) */ @@ -210,6 +198,71 @@ private: * the slave */ void sendMIDIrewind(); + + /* lineInRec + Records from line in. */ + + void lineInRec(float *inBuf, unsigned frame); + + /* ProcessLineIn + Computes line in peaks, plus handles "hear what you're playin'" thing. */ + + void processLineIn(float *inBuf, unsigned frame); + + /* clearAllBuffers + Cleans up every buffer, both in Mixer and in channels. */ + + void clearAllBuffers(float *outBuf, unsigned bufferSize); + + /* readActions + Reads all recorded actions. */ + + void readActions(unsigned frame); + + /* doQuantize + Computes quantization on 'rewind' button and all channels. */ + + void doQuantize(unsigned frame); + + /* sumChannels + Sums channels, i.e. lets them add sample frames to their virtual channels. + This is required for CHANNEL_SAMPLE only */ + + void sumChannels(unsigned frame); + + /* renderMetronome + Generates metronome when needed and pastes it to the output buffer. */ + + void renderMetronome(float *outBuf, unsigned frame); + + /* renderIO + Final processing stage. Take each channel and process it (i.e. copy its + content to the output buffer). Process plugins too, if any. */ + + void renderIO(float *outBuf, float *inBuf); + + /* limitOutput + Applies a very dumb hard limiter. */ + + void limitOutput(float *outBuf, unsigned frame); + + /* computePeak */ + + void computePeak(float *outBuf, unsigned frame); + + /* finalizeOutput + Last touches after the output has been rendered: apply inToOut if any, apply + output volume. */ + + void finalizeOutput(float *outBuf, unsigned frame); + + /* test* + Checks if the sequencer has reached a specific point (bar, first beat or + last frame). */ + + void testBar(unsigned frame); + void testFirstBeat(unsigned frame); + void testLastBeat(); }; #endif diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp index f965e02..e3d1945 100644 --- a/src/core/mixerHandler.cpp +++ b/src/core/mixerHandler.cpp @@ -34,9 +34,10 @@ #endif #include -#include "../utils/utils.h" +#include "../utils/fs.h" +#include "../utils/string.h" #include "../utils/log.h" -#include "../glue/glue.h" +#include "../glue/main.h" #include "../glue/channel.h" #include "mixerHandler.h" #include "kernelMidi.h" @@ -201,83 +202,90 @@ void mh_rewindSequencer() /* -------------------------------------------------------------------------- */ -SampleChannel *mh_startInputRec() +bool mh_startInputRec() { - /* search for the next available channel */ + int channelsReady = 0; - SampleChannel *chan = NULL; for (unsigned i=0; itype == CHANNEL_SAMPLE) - if (((SampleChannel*) G_Mixer.channels.at(i))->canInputRec()) { - chan = (SampleChannel*) G_Mixer.channels.at(i); - break; - } - } - /* no chans available? */ + if (!G_Mixer.channels.at(i)->canInputRec()) + continue; - if (chan == NULL) - return NULL; + SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); - Wave *w = new Wave(); - if (!w->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate)) - return NULL; + /* Allocate empty sample for the current channel. */ + + if (!ch->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate, G_Patch.lastTakeId)) + { + gu_log("[mh_startInputRec] unable to allocate new Wave in chan %d!\n", + ch->index); + continue; + } + + /* Increase lastTakeId until the sample name TAKE-[n] is unique */ + + while (!mh_uniqueSampleName(ch, ch->wave->name)) { + G_Patch_DEPR_.lastTakeId++; + G_Patch.lastTakeId++; + ch->wave->name = "TAKE-" + gu_itoa(G_Patch.lastTakeId); + } - /* increase lastTakeId until the sample name TAKE-[n] is unique */ + gu_log("[mh_startInputRec] start input recs using chan %d with size %d " + "frame=%d\n", ch->index, G_Mixer.totalFrames, G_Mixer.inputTracker); - char name[32]; - sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); - while (!mh_uniqueSamplename(chan, name)) { - G_Patch_DEPR_.lastTakeId++; - G_Patch.lastTakeId++; - sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); + channelsReady++; } - chan->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate, G_Patch_DEPR_.lastTakeId); - G_Mixer.chanInput = chan; + if (channelsReady > 0) { + G_Mixer.recording = true; + /* start to write from the actualFrame, not the beginning */ + /** FIXME: this should be done before wave allocation */ + G_Mixer.inputTracker = G_Mixer.actualFrame; + return true; + } + return false; +} - /* start to write from the actualFrame, not the beginning */ - /** FIXME: move this before wave allocation*/ - G_Mixer.inputTracker = G_Mixer.actualFrame; +/* -------------------------------------------------------------------------- */ - gLog( - "[mh] start input recs using chan %d with size %d, frame=%d\n", - chan->index, G_Mixer.totalFrames, G_Mixer.inputTracker - ); - return chan; +void mh_stopInputRec() +{ + G_Mixer.mergeVirtualInput(); + G_Mixer.recording = false; + G_Mixer.waitRec = 0; // in case delay compensation is in use + gu_log("[mh] stop input recs\n"); } /* -------------------------------------------------------------------------- */ -SampleChannel *mh_stopInputRec() +bool mh_hasArmedSampleChannels() { - gLog("[mh] stop input recs\n"); - G_Mixer.mergeVirtualInput(); - SampleChannel *ch = G_Mixer.chanInput; - G_Mixer.chanInput = NULL; - G_Mixer.waitRec = 0; // if delay compensation is in use - return ch; + for (unsigned i=0; itype == CHANNEL_SAMPLE && ch->armed) + return true; + } + return false; } /* -------------------------------------------------------------------------- */ -bool mh_uniqueSamplename(SampleChannel *ch, const char *name) +bool mh_uniqueSampleName(SampleChannel *ch, const string &name) { for (unsigned i=0; itype == CHANNEL_SAMPLE) { - SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i); - if (other->wave != NULL) - if (!strcmp(name, other->wave->name.c_str())) - return false; - } - } + if (ch == G_Mixer.channels.at(i)) // skip itself + continue; + if (G_Mixer.channels.at(i)->type != CHANNEL_SAMPLE) + continue; + SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i); + if (other->wave != NULL && name == other->wave->name) + return false; } return true; } diff --git a/src/core/mixerHandler.h b/src/core/mixerHandler.h index c624d26..9c33b1c 100644 --- a/src/core/mixerHandler.h +++ b/src/core/mixerHandler.h @@ -31,12 +31,7 @@ #define MIXERHANDLER_H -#include -#include "recorder.h" -#include "patch.h" - - -using std::vector; +#include /* stopSequencer @@ -64,14 +59,20 @@ void mh_readPatch(); * the chan number chosen, otherwise -1 if there are no more empty * channels available. */ -SampleChannel *mh_startInputRec(); +bool mh_startInputRec(); -SampleChannel *mh_stopInputRec(); +void mh_stopInputRec(); /* uniqueSamplename * return true if samplename 'n' is unique. Requires SampleChannel *ch * in order to skip check against itself. */ -bool mh_uniqueSamplename(class SampleChannel *ch, const char *name); +bool mh_uniqueSampleName(class SampleChannel *ch, const std::string &s); + +/* hasArmedSampleChannels +Tells whether Mixer has one or more sample channels armed for input +recording. */ + +bool mh_hasArmedSampleChannels(); #endif diff --git a/src/core/patch.cpp b/src/core/patch.cpp index 1cc2653..dbc1aa7 100644 --- a/src/core/patch.cpp +++ b/src/core/patch.cpp @@ -27,24 +27,16 @@ * -------------------------------------------------------------------------- */ -#include #include "../utils/log.h" -#include "../utils/utils.h" -#include "../gui/dialogs/gd_mainWindow.h" -#include "../gui/elems/ge_keyboard.h" -#include "patch.h" +#include "../utils/string.h" #include "const.h" -#include "init.h" -#include "recorder.h" #include "conf.h" -#include "wave.h" #include "mixer.h" -#include "channel.h" +#include "patch.h" -extern Mixer G_Mixer; -extern Conf G_Conf; -extern gdMainWindow *mainWin; +extern Mixer G_Mixer; +extern Conf G_Conf; void Patch::init() @@ -77,7 +69,7 @@ int Patch::write(const string &file) #endif if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) { - gLog("[Patch::write] unable to write patch file!\n"); + gu_log("[Patch::write] unable to write patch file!\n"); return 0; } return 1; @@ -91,7 +83,7 @@ int Patch::read(const string &file) { jRoot = json_load_file(file.c_str(), 0, &jError); if (!jRoot) { - gLog("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text); + gu_log("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text); return PATCH_UNREADABLE; } @@ -226,6 +218,7 @@ void Patch::writeChannels(json_t *jContainer, vector *channels) json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, json_integer(channel.midiInKeyPress)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, json_integer(channel.midiInKeyRel)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, json_integer(channel.midiInKill)); + json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM, json_integer(channel.midiInArm)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, json_integer(channel.midiInVolume)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, json_integer(channel.midiInMute)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, json_integer(channel.midiInSolo)); @@ -296,7 +289,7 @@ bool Patch::readColumns(json_t *jContainer) json_t *jColumn; json_array_foreach(jColumns, columnIndex, jColumn) { - string columnIndexStr = "column " + gItoa(columnIndex); + string columnIndexStr = "column " + gu_itoa(columnIndex); if (!checkObject(jColumn, columnIndexStr.c_str())) return 0; @@ -323,7 +316,7 @@ bool Patch::readChannels(json_t *jContainer) json_t *jChannel; json_array_foreach(jChannels, channelIndex, jChannel) { - string channelIndexStr = "channel " + gItoa(channelIndex); + string channelIndexStr = "channel " + gu_itoa(channelIndex); if (!checkObject(jChannel, channelIndexStr.c_str())) return 0; @@ -342,6 +335,7 @@ bool Patch::readChannels(json_t *jContainer) if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, channel.midiInKeyPress)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, channel.midiInKeyRel)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, channel.midiInKill)) return 0; + if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM, channel.midiInArm)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, channel.midiInVolume)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, channel.midiInMute)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, channel.midiInSolo)) return 0; diff --git a/src/core/patch.h b/src/core/patch.h index ba1cd33..99ef6a1 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -34,9 +34,7 @@ #include #include #include -#include "../utils/utils.h" #include "dataStorageJson.h" -#include "const.h" using std::string; @@ -79,6 +77,7 @@ public: uint32_t midiInKeyPress; uint32_t midiInKeyRel; uint32_t midiInKill; + uint32_t midiInArm; uint32_t midiInVolume; uint32_t midiInMute; uint32_t midiInSolo; diff --git a/src/core/patch_DEPR_.cpp b/src/core/patch_DEPR_.cpp index 7c30284..99010a0 100644 --- a/src/core/patch_DEPR_.cpp +++ b/src/core/patch_DEPR_.cpp @@ -29,7 +29,7 @@ #include #include "../utils/log.h" -#include "../utils/utils.h" +#include "../utils/fs.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/elems/ge_keyboard.h" #include "patch_DEPR_.h" @@ -43,8 +43,9 @@ #include "channel.h" -extern Mixer G_Mixer; -extern Conf G_Conf; +extern Mixer G_Mixer; +extern Conf G_Conf; +extern Recorder G_Recorder; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif @@ -61,7 +62,7 @@ int Patch_DEPR_::open(const char *file) return PATCH_INVALID; version = atof(getValue("versionf").c_str()); - gLog("[patch_DEPR_] open patch version %f\n", version); + gu_log("[patch_DEPR_] open patch version %f\n", version); return PATCH_READ_OK; } @@ -469,7 +470,7 @@ uint32_t Patch_DEPR_::getMidiValue(int i, const char *c) int Patch_DEPR_::readRecs() { - gLog("[patch_DEPR_] Reading recs...\n"); + gu_log("[patch_DEPR_] Reading recs...\n"); unsigned numrecs = atoi(getValue("numrecs").c_str()); @@ -482,7 +483,7 @@ int Patch_DEPR_::readRecs() sprintf(tmpbuf, "recframe%d", i); sscanf(getValue(tmpbuf).c_str(), "%d %d", &frame, &recPerFrame); -//gLog("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame); +//gu_log("processing frame=%d, recPerFrame=%d\n", frame, recPerFrame); for (int k=0; kstatus & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) { if (version < 0.83f) - recorder::rec(ch->index, type, frame, iValue_fix, fValue); + G_Recorder.rec(ch->index, type, frame, iValue_fix, fValue); else - recorder::rec(ch->index, type, frame, iValue, fValue); + G_Recorder.rec(ch->index, type, frame, iValue, fValue); } } } @@ -526,7 +527,7 @@ int Patch_DEPR_::readRecs() #ifdef WITH_VST int Patch_DEPR_::readPlugins() { - gLog("[patch_DEPR_] Reading plugins...\n"); + gu_log("[patch_DEPR_] Reading plugins...\n"); int globalOut = 1; diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index 740bb70..bf4a1c4 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -49,16 +49,16 @@ void Plugin::init() status = 1; if (getActiveEditor() != NULL) { - gLog("[Plugin::init] plugin has an already active editor!\n"); + gu_log("[Plugin::init] plugin has an already active editor!\n"); return; } ui = createEditorIfNeeded(); if (ui == NULL) { - gLog("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n"); + gu_log("[Plugin::init] unable to create editor, the plugin might be GUI-less!\n"); return; } - gLog("[Plugin::init] editor initialized and ready\n"); + gu_log("[Plugin::init] editor initialized and ready\n"); } @@ -68,7 +68,7 @@ void Plugin::init() void Plugin::showEditor(void *parent) { if (ui == NULL) { - gLog("[Plugin::showEditor] can't show editor!\n"); + gu_log("[Plugin::showEditor] can't show editor!\n"); return; } ui->setOpaque(true); diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp index 9f31f2e..f95a966 100644 --- a/src/core/pluginHost.cpp +++ b/src/core/pluginHost.cpp @@ -31,10 +31,8 @@ #include "../utils/log.h" -#include "../utils/utils.h" -#include "mixer.h" +#include "const.h" #include "channel.h" -#include "midiChannel.h" #include "plugin.h" #include "pluginHost.h" @@ -53,7 +51,7 @@ PluginHost::~PluginHost() void PluginHost::init(int _buffersize, int _samplerate) { - gLog("[PluginHost::init] initialize with buffersize=%d, samplerate=%d\n", + gu_log("[PluginHost::init] initialize with buffersize=%d, samplerate=%d\n", _buffersize, _samplerate); messageManager = juce::MessageManager::getInstance(); @@ -62,7 +60,9 @@ void PluginHost::init(int _buffersize, int _samplerate) buffersize = _buffersize; missingPlugins = false; //unknownPluginList.empty(); - loadList(gGetHomePath() + G_SLASH + "plugins.xml"); + loadList(gu_getHomePath() + G_SLASH + "plugins.xml"); + + pthread_mutex_init(&mutex_midi, NULL); } @@ -72,8 +72,8 @@ void PluginHost::init(int _buffersize, int _samplerate) int PluginHost::scanDir(const string &dirpath, void (*callback)(float progress, void *p), void *p) { - gLog("[PluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str()); - gLog("[PluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes()); + gu_log("[PluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str()); + gu_log("[PluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes()); knownPluginList.clear(); // clear up previous plugins @@ -85,13 +85,13 @@ int PluginHost::scanDir(const string &dirpath, void (*callback)(float progress, bool cont = true; juce::String name; while (cont) { - gLog("[PluginHost::scanDir] scanning '%s'\n", name.toRawUTF8()); + gu_log("[PluginHost::scanDir] scanning '%s'\n", name.toRawUTF8()); cont = scanner.scanNextFile(false, name); if (callback) callback(scanner.getProgress(), p); } - gLog("[PluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes()); + gu_log("[PluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes()); return knownPluginList.getNumTypes(); } @@ -103,7 +103,7 @@ int PluginHost::saveList(const string &filepath) { int out = knownPluginList.createXml()->writeToFile(juce::File(filepath), ""); if (!out) - gLog("[PluginHost::saveList] unable to save plugin list to %s\n", filepath.c_str()); + gu_log("[PluginHost::saveList] unable to save plugin list to %s\n", filepath.c_str()); return out; } @@ -138,7 +138,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, juce::PluginDescription *pd = knownPluginList.getTypeForFile(fid); if (!pd) { - gLog("[PluginHost::addPlugin] no plugin found with fid=%s!\n", fid.c_str()); + gu_log("[PluginHost::addPlugin] no plugin found with fid=%s!\n", fid.c_str()); missingPlugins = true; unknownPluginList.push_back(fid); return NULL; @@ -146,7 +146,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, Plugin *p = (Plugin *) pluginFormat.createInstanceFromDescription(*pd, samplerate, buffersize); if (!p) { - gLog("[PluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str()); + gu_log("[PluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str()); missingPlugins = true; return NULL; } @@ -157,7 +157,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, p->init(); p->prepareToPlay(samplerate, buffersize); - gLog("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str()); + gu_log("[PluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str()); /* Try to inject the plugin as soon as possible. */ @@ -171,7 +171,7 @@ Plugin *PluginHost::addPlugin(const string &fid, int stackType, } } - gLog("[PluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n", + gu_log("[PluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n", fid.c_str(), p->getName().toStdString().c_str(), stackType, pStack->size()); return p; @@ -186,12 +186,12 @@ Plugin *PluginHost::addPlugin(int index, int stackType, pthread_mutex_t *mutex, { juce::PluginDescription *pd = knownPluginList.getType(index); if (pd) { - gLog("[PluginHost::addPlugin] plugin found, uid=%s, name=%s...\n", + gu_log("[PluginHost::addPlugin] plugin found, uid=%s, name=%s...\n", pd->fileOrIdentifier.toStdString().c_str(), pd->name.toStdString().c_str()); return addPlugin(pd->fileOrIdentifier.toStdString(), stackType, mutex, ch); } else { - gLog("[PluginHost::addPlugin] no plugins found at index=%d!\n", index); + gu_log("[PluginHost::addPlugin] no plugins found at index=%d!\n", index); return NULL; } } @@ -258,7 +258,7 @@ PluginHost::PluginInfo PluginHost::getAvailablePluginInfo(int i) pi.isInstrument = pd->isInstrument; /* if (!p) { - gLog("[PluginHost::getAvailablePlugin] unable to create plugin instance!\n"); + gu_log("[PluginHost::getAvailablePlugin] unable to create plugin instance!\n"); return NULL; } */ @@ -303,7 +303,7 @@ void PluginHost::freeStack(int stackType, pthread_mutex_t *mutex, Channel *ch) break; } } - gLog("[PluginHost::freeStack] stack type=%d freed\n", stackType); + gu_log("[PluginHost::freeStack] stack type=%d freed\n", stackType); } @@ -326,17 +326,29 @@ void PluginHost::processStack(float *buffer, int stackType, Channel *ch) audioBuffer.setSample(1, i, buffer[(i*2)+1]); } - /* hardcore processing. At the end we swap input and output, so that - * the N-th plugin will process the result of the plugin N-1. */ + /* Hardcore processing. At the end we swap input and output, so that he N-th + plugin will process the result of the plugin N-1. Part of this loop must be + guarded by mutexes, i.e. the MIDI process part. You definitely don't want + a situation like the following one: + processBlock(...) + [a new midi event from kernelMidi thread] + clearMidiBuffer() + The midi event in between would be surely lost, deleted by clearMidiBuffer! */ for (unsigned i=0; isize(); i++) { Plugin *plugin = pStack->at(i); if (plugin->getStatus() != 1 || plugin->isSuspended() || plugin->isBypassed()) continue; - juce::MidiBuffer midiBuffer; - if (ch) // ch might be null if stackType is MASTER_IN or MASTER_OUT - midiBuffer = ch->getPluginMidiEvents(); - plugin->processBlock(audioBuffer, midiBuffer); + if (ch) { // ch might be null if stackType is MASTER_IN/OUT + pthread_mutex_lock(&mutex_midi); + plugin->processBlock(audioBuffer, ch->getPluginMidiEvents()); + ch->clearMidiBuffer(); + pthread_mutex_unlock(&mutex_midi); + } + else { + juce::MidiBuffer midiBuffer; // empty buffer + plugin->processBlock(audioBuffer, midiBuffer); + } } /* converting buffer from Juce to Giada. A note for the future: if we @@ -389,11 +401,11 @@ void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, if (lockStatus == 0) { std::swap(pStack->at(indexA), pStack->at(indexB)); pthread_mutex_unlock(mutex); - gLog("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB); + gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB); return; } //else - //gLog("[pluginHost] waiting for mutex...\n"); + //gu_log("[pluginHost] waiting for mutex...\n"); } } @@ -406,37 +418,30 @@ void PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex, { vector *pStack = getStack(stackType, ch); - /* try to delete the plugin until succeed. G_Mixer has priority. */ - for (unsigned i=0; isize(); i++) { Plugin *pPlugin = pStack->at(i); - if (pPlugin->getId() == id) { - if (pPlugin->getStatus() == 0) { // no frills if plugin is missing - delete pPlugin; - pStack->erase(pStack->begin() + i); - gLog("[pluginHost::freePlugin] plugin id=%d removed with no frills, since it had status=0\n", id); - return; - } - else { - int lockStatus; - while (true) { - lockStatus = pthread_mutex_trylock(mutex); - if (lockStatus == 0) { - pPlugin->suspendProcessing(true); - pPlugin->releaseResources(); - delete pPlugin; - pStack->erase(pStack->begin() + i); - pthread_mutex_unlock(mutex); - gLog("[pluginHost::freePlugin] plugin id=%d removed\n", id); - return; - } - //else - //gLog("[pluginHost] waiting for mutex...\n"); - } - } + if (pPlugin->getId() != id) + continue; + if (pPlugin->getStatus() == 0) { // no frills if plugin is missing + delete pPlugin; + pStack->erase(pStack->begin() + i); + gu_log("[pluginHost::freePlugin] plugin id=%d removed with no frills, since it had status=0\n", id); + return; + } + + while (true) { + if (pthread_mutex_trylock(mutex) != 0) + continue; + pPlugin->suspendProcessing(true); + pPlugin->releaseResources(); + delete pPlugin; + pStack->erase(pStack->begin() + i); + pthread_mutex_unlock(mutex); + gu_log("[pluginHost::freePlugin] plugin id=%d removed\n", id); + return; } } - gLog("[pluginHost::freePlugin] plugin id=%d not found\n", id); + gu_log("[pluginHost::freePlugin] plugin id=%d not found\n", id); } @@ -446,7 +451,7 @@ void PluginHost::freePlugin(int id, int stackType, pthread_mutex_t *mutex, void PluginHost::runDispatchLoop() { messageManager->runDispatchLoopUntil(10); - //gLog("[PluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent()); + //gu_log("[PluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent()); } @@ -473,7 +478,7 @@ int PluginHost::clonePlugin(Plugin *src, int stackType, pthread_mutex_t *mutex, juce::PluginDescription pd = src->getPluginDescription(); Plugin *p = addPlugin(pd.fileOrIdentifier.toStdString(), stackType, mutex, ch); if (!p) { - gLog("[PluginHost::clonePlugin] unable to add new plugin to stack!\n"); + gu_log("[PluginHost::clonePlugin] unable to add new plugin to stack!\n"); return 0; } for (int k=0; kgetNumParameters(); k++) { @@ -513,36 +518,5 @@ void PluginHost::sortPlugins(int method) } } -/* -------------------------------------------------------------------------- */ - - -void PluginHost::processStackOffline(float *buffer, int stackType, Channel *ch, int size) -{ -#if 0 - /* call processStack on the entire size of the buffer. How many cycles? - * size / (kernelAudio::realBufsize*2) (ie. internal bufsize) */ - - /** FIXME 1 - calling processStack is slow, due to its internal buffer - * conversions. We should also call processOffline from VST sdk */ - - int index = 0; - int step = kernelAudio::realBufsize*2; - - while (index <= size) { - int left = index+step-size; - if (left < 0) - processStack(&buffer[index], stackType, ch); - - /** FIXME 2 - we left out the last part of buffer, because size % step != 0. - * we should process the last chunk in a separate buffer, padded with 0 */ - - //else - // gLog("chunk of buffer left, size=%d\n", left); - - index+=step; - } -#endif -} - #endif // #ifdef WITH_VST diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h index ac741e2..c1f0a51 100644 --- a/src/core/pluginHost.h +++ b/src/core/pluginHost.h @@ -197,11 +197,6 @@ public: void runDispatchLoop(); - /* processStackOffline - * apply the fx list to a longer chunk of data */ - - void processStackOffline(float *buffer, int stackType, class Channel *ch, int size); - /* freeAllStacks * Free everything. */ @@ -219,6 +214,8 @@ public: bool hasMissingPlugins() { return missingPlugins; }; void sortPlugins(int sortMethod); + + pthread_mutex_t mutex_midi; }; #endif diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index 53864b0..57958c7 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -3,7 +3,6 @@ * Giada - Your Hardcore Loopmachine * * recorder - * Action recorder. * * ----------------------------------------------------------------------------- * @@ -29,7 +28,8 @@ #include -#include "recorder.h" +#include "../utils/log.h" +#include "../utils/fs.h" #include "const.h" #include "mixer.h" #include "mixerHandler.h" @@ -39,31 +39,23 @@ #include "conf.h" #include "channel.h" #include "sampleChannel.h" -#include "../utils/log.h" -#include "../utils/utils.h" +#include "recorder.h" +extern KernelAudio G_KernelAudio; extern Mixer G_Mixer; -extern Patch_DEPR_ f_patch; -extern Conf G_Conf; -namespace recorder +Recorder::Recorder() + : active (false), + sortedActions(false) { -vector frames; -vector< vector > global; -vector actions; - -bool active = false; -bool sortedActions = false; - -composite cmp; - +} /* -------------------------------------------------------------------------- */ -void init() +void Recorder::init() { sortedActions = false; active = false; @@ -74,24 +66,28 @@ void init() /* -------------------------------------------------------------------------- */ -bool canRec(Channel *ch) +bool Recorder::canRec(Channel *ch) { /* NO recording if: * recorder is inactive * mixer is not running - * mixer is recording a take in this channel ch + * mixer is recording a take somewhere * channel is empty */ - if (!active || !G_Mixer.running || G_Mixer.chanInput == ch || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL)) - return 0; - return 1; + if (!active || + !G_Mixer.running || + G_Mixer.recording || + (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL) + ) + return false; + return true; } /* -------------------------------------------------------------------------- */ -void rec(int index, int type, int frame, uint32_t iValue, float fValue) +void Recorder::rec(int index, int type, int frame, uint32_t iValue, float fValue) { /* make sure frame is even */ @@ -149,12 +145,11 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue) /* don't activate the channel (readActions == false), it's up to * the other layers */ - Channel *ch = G_Mixer.getChannelByIndex(index); - ch->hasActions = true; + G_Mixer.getChannelByIndex(index)->hasActions = true; sortedActions = false; - gLog("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", + gu_log("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (0x%X) fValue=%f\n", a->type, a->frame, a->chan, a->iValue, a->iValue, a->fValue); //print(); } @@ -163,9 +158,9 @@ void rec(int index, int type, int frame, uint32_t iValue, float fValue) /* -------------------------------------------------------------------------- */ -void clearChan(int index) +void Recorder::clearChan(int index) { - gLog("[REC] clearing chan %d...\n", index); + gu_log("[REC] clearing chan %d...\n", index); for (unsigned i=0; iiValue == iValue && a->fValue == fValue); if (doit) { + // TODO - wft? just do: while (true); if (pthread_mutex_trylock(&G_Mixer.mutex_recs)) int lockStatus = 0; while (lockStatus == 0) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs); @@ -255,7 +252,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa break; } else - gLog("[REC] delete action: waiting for mutex...\n"); + gu_log("[REC] delete action: waiting for mutex...\n"); } } } @@ -264,11 +261,11 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa if (found) { optimize(); setChanHasActionsStatus(chan); - gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", + gu_log("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } else - gLog("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", + gu_log("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } @@ -276,7 +273,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iVa /* -------------------------------------------------------------------------- */ -void deleteActions(int chan, int frame_a, int frame_b, char type) +void Recorder::deleteActions(int chan, int frame_a, int frame_b, char type) { sortActions(); vector dels; @@ -293,19 +290,12 @@ void deleteActions(int chan, int frame_a, int frame_b, char type) /* -------------------------------------------------------------------------- */ -void clearAll() +void Recorder::clearAll() { while (global.size() > 0) { for (unsigned i=0; itype == ACTION_MIDI) - free(global.at(i).at(k)->event); -#endif -#endif + for (unsigned k=0; kchan == chan && (type & a->type) == a->type) { - if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) { + //if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) { + if (iValue == 0 || (iValue != 0 && (iValue & a->iValue) == a->iValue )) { *out = global.at(i).at(j); return 1; } @@ -554,7 +546,7 @@ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue) /* -------------------------------------------------------------------------- */ -int getAction(int chan, char action, int frame, struct action **out) +int Recorder::getAction(int chan, char action, int frame, struct action **out) { for (unsigned i=0; itype == cmp.a2.type) { - int truncFrame = cmp.a1.frame-kernelAudio::realBufsize; + int truncFrame = cmp.a1.frame - G_KernelAudio.realBufsize; if (truncFrame < 0) truncFrame = 0; - gLog("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type); + gu_log("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type); rec(index, cmp.a2.type, truncFrame); } } @@ -614,7 +606,7 @@ void startOverdub(int index, char actionMask, int frame) /* -------------------------------------------------------------------------- */ -void stopOverdub(int frame) +void Recorder::stopOverdub(int frame) { cmp.a2.frame = frame; bool ringLoop = false; @@ -625,13 +617,13 @@ void stopOverdub(int frame) if (cmp.a2.frame < cmp.a1.frame) { ringLoop = true; - gLog("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame); + gu_log("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame); rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames); // record at the end of the sequencer } else if (cmp.a2.frame == cmp.a1.frame) { nullLoop = true; - gLog("[REC] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame); + gu_log("[REC] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame); deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values } @@ -655,7 +647,7 @@ void stopOverdub(int frame) int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act); if (res == 1) { if (act->type == cmp.a2.type) { - gLog("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type); + gu_log("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type); deleteAction(act->chan, act->frame, act->type, false); // false == don't check values } } @@ -666,15 +658,13 @@ void stopOverdub(int frame) /* -------------------------------------------------------------------------- */ -void print() +void Recorder::print() { - gLog("[REC] ** print debug **\n"); + gu_log("[REC] ** print debug **\n"); for (unsigned i=0; itype, global.at(i).at(j)->chan, global.at(i).at(j)->frame); + gu_log(" action %d | chan %d | frame %d\n", global.at(i).at(j)->type, global.at(i).at(j)->chan, global.at(i).at(j)->frame); } } } - -} // namespace diff --git a/src/core/recorder.h b/src/core/recorder.h index 95a8b65..307b408 100644 --- a/src/core/recorder.h +++ b/src/core/recorder.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * recorder * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,156 +24,166 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + #ifndef RECORDER_H #define RECORDER_H -#include -#include + +#ifdef __APPLE__ // our compiler still doesn't know about cstdint (c++11 stuff) + #include +#else + #include +#endif #include -#include "../utils/utils.h" -#include "const.h" -#include "mixer.h" using std::vector; -/* - * [global0]-->[vector<_action*>0]-->[a0][a1][a2] 0[frames1] - * [global1]-->[vector<_action*>1]-->[a0][a1][a2] 1[frames2] - * [global2]-->[vector<_action*>2]-->[a0][a1][a2] 2[frames3] - * [global3]-->[vector<_action*>3]-->[a0][a1][a2] 3[frames4] - * */ - -namespace recorder +class Recorder { -/* action - * struct containing fields to describe an atomic action. Note from - * VST sdk: parameter values, like all VST parameters, are declared as - * floats with an inclusive range of 0.0 to 1.0 (fValue). */ +public: -struct action -{ - int chan; // channel index, i.e. Channel->index - int type; - int frame; // redundant info, used by helper functions - float fValue; // used only for envelopes (volumes, vst params). - uint32_t iValue; // used only for MIDI events -}; + Recorder(); -/* composite - * a group of two actions (keypress+keyrel, muteon+muteoff) used during - * the overdub process */ + /* action + * struct containing fields to describe an atomic action. Note from + * VST sdk: parameter values, like all VST parameters, are declared as + * floats with an inclusive range of 0.0 to 1.0 (fValue). */ -struct composite -{ - action a1; - action a2; -}; + struct action + { + int chan; // channel index, i.e. Channel->index + int type; + int frame; // redundant info, used by helper functions + float fValue; // used only for envelopes (volumes, vst params). + uint32_t iValue; // used only for MIDI events + }; + + /* [global0]-->[vector<_action*>0]-->[a0][a1][a2] 0[frames1] + * [global1]-->[vector<_action*>1]-->[a0][a1][a2] 1[frames2] + * [global2]-->[vector<_action*>2]-->[a0][a1][a2] 2[frames3] + * [global3]-->[vector<_action*>3]-->[a0][a1][a2] 3[frames4] */ + + vector frames; // frame counter (sentinel) frames.size == global.size + vector> global; // container of containers of actions + vector actions; // container of actions -extern vector frames; // frame counter (sentinel) frames.size == global.size -extern vector< vector > global; // container of containers of actions -extern vector actions; // container of actions + bool active; + bool sortedActions; // are actions sorted via sortActions()? -extern bool active; -extern bool sortedActions; // are actions sorted via sortActions()? + /* init + * everything starts from here. */ -/* init - * everything starts from here. */ + void init(); -void init(); + /* setChanHasActionsStatus + * Check if the channel has at least one action recorded. If false, sets + * ch->hasActions = false. Used after an action deletion. */ -/* setChanHasActionsStatus - * Check if the channel has at least one action recorded. If false, sets - * ch->hasActions = false. Used after an action deletion. */ + void setChanHasActionsStatus(int chan); -void setChanHasActionsStatus(int chan); + /* canRec + * can a channel rec an action? Call this one BEFORE rec(). */ -/* canRec - * can a channel rec an action? Call this one BEFORE rec(). */ + bool canRec(class Channel *ch); -bool canRec(Channel *ch); + /* rec + * record an action. */ -/* rec - * record an action. */ + void rec(int chan, int action, int frame, uint32_t iValue=0, + float fValue=0.0f); -void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f); + /* clearChan + * clear all actions from a channel. */ -/* clearChan - * clear all actions from a channel. */ + void clearChan(int chan); -void clearChan(int chan); + /* clearAction + * clear the 'action' action type from a channel. */ -/* clearAction - * clear the 'action' action type from a channel. */ + void clearAction(int chan, char action); -void clearAction(int chan, char action); + /* deleteAction + * delete ONE action. Useful in the action editor. 'type' can be a mask. */ -/* deleteAction - * delete ONE action. Useful in the action editor. 'type' can be a mask. */ + void deleteAction(int chan, int frame, char type, bool checkValues, + uint32_t iValue=0, float fValue=0.0); -void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue=0, float fValue=0.0); + /* deleteActions + * delete A RANGE of actions from frame_a to frame_b in channel 'chan'. + * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */ -/* deleteActions - * delete A RANGE of actions from frame_a to frame_b in channel 'chan'. - * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */ + void deleteActions(int chan, int frame_a, int frame_b, char type); -void deleteActions(int chan, int frame_a, int frame_b, char type); + /* clearAll + * delete everything. */ -/* clearAll - * delete everything. */ + void clearAll(); -void clearAll(); + /* optimize + * clear frames without actions. */ -/* optimize - * clear frames without actions. */ + void optimize(); -void optimize(); + /* sortActions + * sorts actions by frame, asc mode. */ -/* sortActions - * sorts actions by frame, asc mode. */ + void sortActions(); -void sortActions(); + /* updateBpm + * reassign frames by calculating the new bpm value. */ -/* updateBpm - * reassign frames by calculating the new bpm value. */ + void updateBpm(float oldval, float newval, int oldquanto); -void updateBpm(float oldval, float newval, int oldquanto); + /* updateSamplerate + * reassign frames taking in account the samplerate. If f_system == + * f_patch nothing changes, otherwise the conversion is mandatory. */ -/* updateSamplerate - * reassign frames taking in account the samplerate. If f_system == - * f_patch nothing changes, otherwise the conversion is mandatory. */ + void updateSamplerate(int systemRate, int patchRate); -void updateSamplerate(int systemRate, int patchRate); + void expand(int old_fpb, int new_fpb); + void shrink(int new_fpb); -void expand(int old_fpb, int new_fpb); -void shrink(int new_fpb); + /* getNextAction + * Return the nearest action in chan 'chan' of type 'action' starting + * from 'frame'. Action can be a bitmask. If iValue != 0 search for + * next action with iValue == iValue: useful for MIDI key_release. iValue + * can be a bitmask. */ -/* getNextAction - * return the nearest action in chan 'chan' of type 'action' starting - * from 'frame'. Action can be a bitmask. If iValue != -1 search for - * next action with iValue == iValue: useful for MIDI key_release. */ + int getNextAction(int chan, char action, int frame, struct action **out, + uint32_t iValue=0); -int getNextAction(int chan, char action, int frame, struct action **out, uint32_t iValue=0); + /* getAction + * return a pointer to action in chan 'chan' of type 'action' at frame + * 'frame'. */ -/* getAction - * return a pointer to action in chan 'chan' of type 'action' at frame - * 'frame'. */ + int getAction(int chan, char action, int frame, struct action **out); -int getAction(int chan, char action, int frame, struct action **out); + /* start/endOverdub */ -/* start/endOverdub */ + void startOverdub(int chan, char action, int frame); + void stopOverdub(int frame); -void startOverdub(int chan, char action, int frame); -void stopOverdub(int frame); +private: -/* print - * debug of the frame stack. */ + /* composite + * a group of two actions (keypress+keyrel, muteon+muteoff) used during + * the overdub process */ -void print(); + struct composite + { + action a1; + action a2; + } cmp; -} // namespace + /* print + * debug of the frame stack. */ + + void print(); + +}; #endif diff --git a/src/core/sampleChannel.cpp b/src/core/sampleChannel.cpp index 3b7d5e1..4489801 100644 --- a/src/core/sampleChannel.cpp +++ b/src/core/sampleChannel.cpp @@ -29,6 +29,7 @@ #include #include "../utils/log.h" +#include "../utils/string.h" #include "sampleChannel.h" #include "patch_DEPR_.h" #include "patch.h" @@ -38,11 +39,16 @@ #include "waveFx.h" #include "mixerHandler.h" #include "kernelMidi.h" +#include "kernelAudio.h" using std::string; +extern Recorder G_Recorder; +extern KernelAudio G_KernelAudio; + + SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf) : Channel (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize, midiMapConf), frameRewind (-1), @@ -60,12 +66,12 @@ SampleChannel::SampleChannel(int bufferSize, MidiMapConf *midiMapConf) fadeoutVol (1.0f), fadeoutTracker (0), fadeoutStep (DEFAULT_FADEOUT_STEP), - readActions (true), + readActions (false), midiInReadActions(0x0), midiInPitch (0x0) { rsmp_state = src_new(SRC_LINEAR, 2, NULL); - pChan = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float)); + pChan = (float *) malloc(G_KernelAudio.realBufsize * 2 * sizeof(float)); } @@ -119,8 +125,8 @@ void SampleChannel::generateUniqueSampleName() { string oldName = wave->name; int k = 1; // Start from k = 1, zero is too nerdy - while (!mh_uniqueSamplename(this, wave->name.c_str())) { - wave->updateName((oldName + "-" + gItoa(k)).c_str()); + while (!mh_uniqueSampleName(this, wave->name)) { + wave->updateName((oldName + "-" + gu_itoa(k)).c_str()); k++; } } @@ -140,7 +146,7 @@ void SampleChannel::clear() if (status & (STATUS_PLAY | STATUS_ENDING)) { tracker = fillChan(vChan, tracker, 0); if (fadeoutOn && fadeoutType == XFADE) { - gLog("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker); + gu_log("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker); fadeoutTracker = fillChan(pChan, fadeoutTracker, 0); } } @@ -154,14 +160,14 @@ void SampleChannel::calcVolumeEnv(int frame) { /* method: check this frame && next frame, then calculate delta */ - recorder::action *a0 = NULL; - recorder::action *a1 = NULL; + Recorder::action *a0 = NULL; + Recorder::action *a1 = NULL; int res; /* get this action on frame 'frame'. It's unlikely that the action * is not found. */ - res = recorder::getAction(index, ACTION_VOLUME, frame, &a0); + res = G_Recorder.getAction(index, ACTION_VOLUME, frame, &a0); if (res == 0) return; @@ -170,10 +176,10 @@ void SampleChannel::calcVolumeEnv(int frame) * and use action at frame number 0 (actions[0]). * res == -2 ACTION_VOLUME not found. This should never happen */ - res = recorder::getNextAction(index, ACTION_VOLUME, frame, &a1); + res = G_Recorder.getNextAction(index, ACTION_VOLUME, frame, &a1); if (res == -1) - res = recorder::getAction(index, ACTION_VOLUME, 0, &a1); + res = G_Recorder.getAction(index, ACTION_VOLUME, 0, &a1); volume_i = a0->fValue; volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f; @@ -278,7 +284,7 @@ void SampleChannel::rewind() /* -------------------------------------------------------------------------- */ -void SampleChannel::parseAction(recorder::action *a, int localFrame, +void SampleChannel::parseAction(Recorder::action *a, int localFrame, int globalFrame, int quantize, bool mixerIsRunning) { if (readActions == false) @@ -287,7 +293,7 @@ void SampleChannel::parseAction(recorder::action *a, int localFrame, switch (a->type) { case ACTION_KEYPRESS: if (mode & SINGLE_ANY) - start(localFrame, false, quantize, mixerIsRunning); + start(localFrame, false, quantize, mixerIsRunning, false, false); break; case ACTION_KEYREL: if (mode & SINGLE_ANY) @@ -494,11 +500,11 @@ void SampleChannel::quantize(int index, int localFrame, int globalFrame) /* this is the moment in which we record the keypress, if the * quantizer is on. SINGLE_PRESS needs overdub */ - if (recorder::canRec(this)) { + if (G_Recorder.canRec(this)) { if (mode == SINGLE_PRESS) - recorder::startOverdub(index, ACTION_KEYS, globalFrame); + G_Recorder.startOverdub(index, ACTION_KEYS, globalFrame); else - recorder::rec(index, ACTION_KEYPRESS, globalFrame); + G_Recorder.rec(index, ACTION_KEYPRESS, globalFrame); } } @@ -603,13 +609,9 @@ void SampleChannel::calcFadeoutStep() void SampleChannel::setReadActions(bool v, bool recsStopOnChanHalt) { - if (v) - readActions = true; - else { - readActions = false; - if (recsStopOnChanHalt) - kill(0); /// FIXME - wrong frame value - } + readActions = v; + if (!readActions && recsStopOnChanHalt) + kill(0); /// FIXME - wrong frame value } @@ -643,7 +645,7 @@ void SampleChannel::setFadeOut(int actionPostFadeout) void SampleChannel::setXFade(int frame) { - gLog("[xFade] frame=%d tracker=%d\n", frame, tracker); + gu_log("[xFade] frame=%d tracker=%d\n", frame, tracker); calcFadeoutStep(); fadeoutOn = true; @@ -697,7 +699,7 @@ void SampleChannel::pushWave(Wave *w) { wave = w; status = STATUS_OFF; - sendMidiLplay(); + sendMidiLplay(); // FIXME - why here?!?! begin = 0; end = wave->size; } @@ -712,14 +714,14 @@ bool SampleChannel::allocEmpty(int frames, int samplerate, int takeId) if (!w->allocEmpty(frames, samplerate)) return false; - w->name = "TAKE-" + gItoa(takeId); - w->pathfile = gGetCurrentPath() + G_SLASH + w->name; + w->name = "TAKE-" + gu_itoa(takeId); + w->pathfile = gu_getCurrentPath() + G_SLASH + w->name; wave = w; status = STATUS_OFF; begin = 0; end = wave->size; - sendMidiLplay(); + sendMidiLplay(); // FIXME - why here?!?! return true; } @@ -728,15 +730,24 @@ bool SampleChannel::allocEmpty(int frames, int samplerate, int takeId) /* -------------------------------------------------------------------------- */ -void SampleChannel::process(float *buffer) +void SampleChannel::process(float *outBuffer, float *inBuffer) { + /* If armed and inbuffer is not null (i.e. input device available), copy input + buffer to vChan: this enables the live recording mode. The vChan will be + overwritten later by PluginHost::processStack, so that you would record "clean" + audio (i.e. not plugin-processed). */ + + if (armed && inBuffer) + for (int i=0; iprocessStack(vChan, PluginHost::CHANNEL, this); #endif for (int j=0; jopen(file)) { - gLog("[SampleChannel] %s: read error\n", file); + gu_log("[SampleChannel] %s: read error\n", file); delete w; return SAMPLE_READ_ERROR; } if (w->channels() > 2) { - gLog("[SampleChannel] %s: unsupported multichannel wave\n", file); + gu_log("[SampleChannel] %s: unsupported multichannel wave\n", file); delete w; return SAMPLE_MULTICHANNEL; } @@ -839,7 +850,7 @@ int SampleChannel::load(const char *file, int samplerate, int rsmpQuality) wfx_monoToStereo(w); if (w->rate() != samplerate) { - gLog("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n", + gu_log("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n", w->rate(), samplerate); w->resample(rsmpQuality, samplerate); } @@ -847,7 +858,7 @@ int SampleChannel::load(const char *file, int samplerate, int rsmpQuality) pushWave(w); generateUniqueSampleName(); - gLog("[SampleChannel] %s loaded in channel %d\n", file, index); + gu_log("[SampleChannel] %s loaded in channel %d\n", file, index); return SAMPLE_LOADED_OK; } @@ -944,8 +955,8 @@ int SampleChannel::readPatch(const string &basePath, int i, Patch *patch, bool SampleChannel::canInputRec() - { - return wave == NULL; +{ + return wave == NULL && armed; } @@ -953,7 +964,7 @@ bool SampleChannel::canInputRec() void SampleChannel::start(int frame, bool doQuantize, int quantize, - bool mixerIsRunning) + bool mixerIsRunning, bool forceStart, bool isUserGenerated) { switch (status) { case STATUS_EMPTY: @@ -962,35 +973,34 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize, { return; } - case STATUS_OFF: { if (mode & LOOP_ANY) { - status = STATUS_WAIT; + if (forceStart) { + status = STATUS_PLAY; + tracker = frame; + } + else + status = STATUS_WAIT; sendMidiLplay(); } else { if (quantize > 0 && mixerIsRunning && doQuantize) qWait = true; else { - - /* fillChan only if frame != 0. If you call fillChan on frame == 0 - a duplicate call to fillChan occurs with loss of data. Yeah, but - what happens if an action really occurs on frame 0 (and it happens, - for example when you start the sequencer from the firt beat)? Cheat - time! Shift a little bit the frame, so that it's no longer zero. */ - status = STATUS_PLAY; sendMidiLplay(); - if (frame == 0) - frame = 2; - //if (frame != 0) + + /* Do fillChan only if this is not a user-generated event (i.e. is an + action read by Mixer). Otherwise clear() will take take of calling + fillChan on the next cycle. */ + + if (!isUserGenerated) tracker = fillChan(vChan, tracker, frame); } } break; } - case STATUS_PLAY: { if (mode == SINGLE_BASIC) @@ -1009,14 +1019,12 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize, } break; } - case STATUS_WAIT: { status = STATUS_OFF; sendMidiLplay(); break; } - case STATUS_ENDING: { status = STATUS_PLAY; @@ -1032,13 +1040,15 @@ void SampleChannel::start(int frame, bool doQuantize, int quantize, int SampleChannel::writePatch(int i, bool isProject, Patch *patch) { + // TODO - this code belongs to an upper level (glue) + int pchIndex = Channel::writePatch(i, isProject, patch); Patch::channel_t *pch = &patch->channels.at(pchIndex); if (wave != NULL) { pch->samplePath = wave->pathfile; if (isProject) - pch->samplePath = gBasename(wave->pathfile); // make it portable + pch->samplePath = gu_basename(wave->pathfile); // make it portable } else pch->samplePath = ""; diff --git a/src/core/sampleChannel.h b/src/core/sampleChannel.h index 9158248..751b999 100644 --- a/src/core/sampleChannel.h +++ b/src/core/sampleChannel.h @@ -89,30 +89,33 @@ public: SampleChannel(int bufferSize, class MidiMapConf *midiMapConf); ~SampleChannel(); - void copy(const Channel *src, pthread_mutex_t *pluginMutex); - - void clear (); - void process (float *buffer); - void start (int frame, bool doQuantize, int quantize, bool mixerIsRunning); - void kill (int frame); - void empty (); - void stopBySeq (bool chansStopOnSeqHalt); - void stop (); - void rewind (); - void setMute (bool internal); - void unsetMute (bool internal); - void reset (int frame); - int load (const char *file, int samplerate, int rsmpQuality); - int readPatch_DEPR_ (const char *file, int i, class Patch_DEPR_ *patch, - int samplerate, int rsmpQuality); - int readPatch (const string &basePath, int i, class Patch *patch, - pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality); - int writePatch (int i, bool isProject, class Patch *patch); - void quantize (int index, int localFrame, int globalFrame); - void onZero (int frame, bool recsStopOnChanHalt); - void onBar (int frame); - void parseAction(recorder::action *a, int localFrame, int globalFrame, - int quantize, bool mixerIsRunning); + void copy(const Channel *src, pthread_mutex_t *pluginMutex) override; + void clear() override; + void process(float *outBuffer, float *inBuffer) override; + void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning, + bool forceStart, bool isUserGenerated) override; + void kill(int frame) override; + void empty() override; + void stopBySeq(bool chansStopOnSeqHalt) override; + void stop() override; + void rewind() override; + void setMute(bool internal) override; + void unsetMute(bool internal) override; + int readPatch_DEPR_(const char *file, int i, class Patch_DEPR_ *patch, + int samplerate, int rsmpQuality) override; + int readPatch(const string &basePath, int i, class Patch *patch, + pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality) override; + int writePatch(int i, bool isProject, class Patch *patch) override; + void quantize(int index, int localFrame, int globalFrame) override; + void onZero(int frame, bool recsStopOnChanHalt) override; + void onBar(int frame) override; + void parseAction(Recorder::action *a, int localFrame, int globalFrame, + int quantize, bool mixerIsRunning) override; + bool canInputRec() override; + + int load(const char *file, int samplerate, int rsmpQuality); + + void reset(int frame); /* fade methods * prepare channel for fade, mixer will take care of the process @@ -165,13 +168,8 @@ public: bool allocEmpty(int frames, int samplerate, int takeId); - /* canInputRec - * true if channel can host a new wave from input recording. */ - - bool canInputRec(); - /* setReadActions - * if enabled, recorder will read actions from this channel. If + * if enabled (v == true), recorder will read actions from this channel. If * recsStopOnChanHalt == true, stop reading actions right away. */ void setReadActions(bool v, bool recsStopOnChanHalt); diff --git a/src/core/wave.cpp b/src/core/wave.cpp index 4bdffc9..7f89e32 100644 --- a/src/core/wave.cpp +++ b/src/core/wave.cpp @@ -31,7 +31,7 @@ #include #include // memcpy #include -#include "../utils/utils.h" +#include "../utils/fs.h" #include "../utils/log.h" #include "init.h" #include "const.h" @@ -81,11 +81,11 @@ Wave::Wave(const Wave &other) int Wave::open(const char *f) { pathfile = f; - name = gStripExt(gBasename(f).c_str()); + name = gu_stripExt(gu_basename(f)); fileIn = sf_open(f, SFM_READ, &inHeader); if (fileIn == NULL) { - gLog("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn)); + gu_log("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn)); pathfile = ""; name = ""; return 0; @@ -119,12 +119,12 @@ int Wave::readData() size = inHeader.frames * inHeader.channels; data = (float *) malloc(size * sizeof(float)); if (data == NULL) { - gLog("[wave] unable to allocate memory\n"); + gu_log("[wave] unable to allocate memory\n"); return 0; } if (sf_read_float(fileIn, data, size) != size) - gLog("[wave] warning: incomplete read!\n"); + gu_log("[wave] warning: incomplete read!\n"); sf_close(fileIn); return 1; @@ -144,13 +144,13 @@ int Wave::writeData(const char *f) fileOut = sf_open(f, SFM_WRITE, &outHeader); if (fileOut == NULL) { - gLog("[wave] unable to open %s for exporting\n", f); + gu_log("[wave] unable to open %s for exporting\n", f); return 0; } int out = sf_write_float(fileOut, data, size); if (out != (int) size) { - gLog("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut)); + gu_log("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut)); return 0; } @@ -186,7 +186,7 @@ int Wave::allocEmpty(unsigned __size, unsigned samplerate) size = __size; data = (float *) malloc(size * sizeof(float)); if (data == NULL) { - gLog("[wave] unable to allocate memory\n"); + gu_log("[wave] unable to allocate memory\n"); return 0; } @@ -213,7 +213,7 @@ int Wave::resample(int quality, int newRate) float *tmp = (float *) malloc(newSize * sizeof(float)); if (!tmp) { - gLog("[wave] unable to allocate memory for resampling\n"); + gu_log("[wave] unable to allocate memory for resampling\n"); return -1; } @@ -224,11 +224,11 @@ int Wave::resample(int quality, int newRate) src_data.output_frames = newSize/2; // in frames, i.e. /2 (stereo) src_data.src_ratio = ratio; - gLog("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2); + gu_log("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2); int ret = src_simple(&src_data, quality, 2); if (ret != 0) { - gLog("[wave] resampling error: %s\n", src_strerror(ret)); + gu_log("[wave] resampling error: %s\n", src_strerror(ret)); return 0; } @@ -245,12 +245,12 @@ int Wave::resample(int quality, int newRate) string Wave::basename(bool ext) const { - return ext ? gBasename(pathfile) : gStripExt(gBasename(pathfile)); + return ext ? gu_basename(pathfile) : gu_stripExt(gu_basename(pathfile)); } string Wave::extension() const { - return gGetExt(pathfile.c_str()); + return gu_getExt(pathfile); } @@ -259,9 +259,9 @@ string Wave::extension() const void Wave::updateName(const char *n) { - string ext = gGetExt(pathfile.c_str()); - name = gStripExt(gBasename(n).c_str()); - pathfile = gDirname(pathfile.c_str()) + G_SLASH + name + "." + ext; + string ext = gu_getExt(pathfile); + name = gu_stripExt(gu_basename(n)); + pathfile = gu_dirname(pathfile) + G_SLASH + name + "." + ext; isLogical = true; /* a wave with updated name must become logical, since the underlying diff --git a/src/core/waveFx.cpp b/src/core/waveFx.cpp index 52b6f1c..5831968 100644 --- a/src/core/waveFx.cpp +++ b/src/core/waveFx.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * waveFx * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,21 +24,17 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ -#include +#include #include "../utils/log.h" -#include "waveFx.h" -#include "channel.h" -#include "mixer.h" #include "wave.h" +#include "waveFx.h" -extern Mixer G_Mixer; - - -float wfx_normalizeSoft(Wave *w) { +float wfx_normalizeSoft(Wave *w) +{ float peak = 0.0f; float abs = 0.0f; for (int i=0; isize; i++) { // i++: both L and R samples @@ -57,15 +53,15 @@ float wfx_normalizeSoft(Wave *w) { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -bool wfx_monoToStereo(Wave *w) { +bool wfx_monoToStereo(Wave *w) +{ unsigned newSize = w->size * 2; float *dataNew = (float *) malloc(newSize * sizeof(float)); if (dataNew == NULL) { - gLog("[wfx] unable to allocate memory for mono>stereo conversion\n"); + gu_log("[wfx] unable to allocate memory for mono>stereo conversion\n"); return 0; } @@ -85,16 +81,16 @@ bool wfx_monoToStereo(Wave *w) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void wfx_silence(Wave *w, int a, int b) { - +void wfx_silence(Wave *w, int a, int b) +{ /* stereo values */ a = a * 2; b = b * 2; - gLog("[wfx] silencing from %d to %d\n", a, b); + gu_log("[wfx] silencing from %d to %d\n", a, b); for (int i=a; idata[i] = 0.0f; @@ -107,10 +103,11 @@ void wfx_silence(Wave *w, int a, int b) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int wfx_cut(Wave *w, int a, int b) { +int wfx_cut(Wave *w, int a, int b) +{ a = a * 2; b = b * 2; @@ -123,11 +120,11 @@ int wfx_cut(Wave *w, int a, int b) { unsigned newSize = w->size-(b-a); float *temp = (float *) malloc(newSize * sizeof(float)); if (temp == NULL) { - gLog("[wfx] unable to allocate memory for cutting\n"); + gu_log("[wfx] unable to allocate memory for cutting\n"); return 0; } - gLog("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2); + gu_log("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2); for (int i=0, k=0; isize; i++) { if (i < a || i >= b) { // left margin always included, in order to keep @@ -143,16 +140,17 @@ int wfx_cut(Wave *w, int a, int b) { w->frames(w->frames() - b - a); w->isEdited = true; - gLog("[wfx] cutting done\n"); + gu_log("[wfx] cutting done\n"); return 1; } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -int wfx_trim(Wave *w, int a, int b) { +int wfx_trim(Wave *w, int a, int b) +{ a = a * 2; b = b * 2; @@ -162,11 +160,11 @@ int wfx_trim(Wave *w, int a, int b) { int newSize = b - a; float *temp = (float *) malloc(newSize * sizeof(float)); if (temp == NULL) { - gLog("[wfx] unable to allocate memory for trimming\n"); + gu_log("[wfx] unable to allocate memory for trimming\n"); return 0; } - gLog("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a); + gu_log("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a); for (int i=a, k=0; idata[i]; @@ -182,11 +180,11 @@ int wfx_trim(Wave *w, int a, int b) { } -/* ------------------------------------------------------------------ */ - +/* -------------------------------------------------------------------------- */ -void wfx_fade(Wave *w, int a, int b, int type) { +void wfx_fade(Wave *w, int a, int b, int type) +{ float m = type == 0 ? 0.0f : 1.0f; float d = 1.0f/(float)(b-a); if (type == 1) @@ -200,14 +198,16 @@ void wfx_fade(Wave *w, int a, int b, int type) { w->data[i+1] *= m; m += d; } -} + w->isEdited = true; +} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void wfx_smooth(Wave *w, int a, int b) { +void wfx_smooth(Wave *w, int a, int b) +{ int d = 32; // 64 if stereo data /* do nothing if fade edges (both of 32 samples) are > than selected @@ -215,7 +215,7 @@ void wfx_smooth(Wave *w, int a, int b) { * values. */ if (d*2 > (b-a)*2) { - gLog("[WFX] selection is too small, nothing to do\n"); + gu_log("[WFX] selection is too small, nothing to do\n"); return; } diff --git a/src/core/waveFx.h b/src/core/waveFx.h index 491b1af..7eae643 100644 --- a/src/core/waveFx.h +++ b/src/core/waveFx.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * waveFx * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef WAVEFX_H diff --git a/src/glue/channel.cpp b/src/glue/channel.cpp index ea4e01b..c1fa9ba 100644 --- a/src/glue/channel.cpp +++ b/src/glue/channel.cpp @@ -29,22 +29,27 @@ #include "../gui/dialogs/gd_mainWindow.h" +#include "../gui/dialogs/gd_editor.h" #include "../gui/elems/ge_keyboard.h" -#include "../gui/elems/ge_channel.h" -#include "../utils/gui_utils.h" +#include "../gui/elems/ge_waveTools.h" +#include "../gui/elems/ge_waveform.h" +#include "../gui/elems/channel.h" +#include "../utils/gui.h" #include "../core/mixerHandler.h" #include "../core/mixer.h" #include "../core/pluginHost.h" #include "../core/conf.h" +#include "../core/wave.h" #include "../core/channel.h" #include "../core/sampleChannel.h" #include "../core/midiChannel.h" -#include "glue.h" +#include "main.h" #include "channel.h" -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; extern Conf G_Conf; +extern Recorder G_Recorder; extern Mixer G_Mixer; #ifdef WITH_VST extern PluginHost G_PluginHost; @@ -54,17 +59,25 @@ extern PluginHost G_PluginHost; using std::string; -int glue_loadChannel(SampleChannel *ch, const char *fname) +static bool __soloSession__ = false; + + +int glue_loadChannel(SampleChannel *ch, const string &fname) { + /* Always stop a channel before loading a new sample in it. This will prevent + issues if tracker is outside the boundaries of the new sample -> segfault. */ + + ch->hardStop(0); + /* save the patch and take the last browser's dir in order to re-use it * the next time */ - G_Conf.samplePath = gDirname(fname); + G_Conf.samplePath = gu_dirname(fname); - int result = ch->load(fname, G_Conf.samplerate, G_Conf.rsmpQuality); + int result = ch->load(fname.c_str(), G_Conf.samplerate, G_Conf.rsmpQuality); if (result == SAMPLE_LOADED_OK) - mainWin->keyboard->updateChannel(ch->guiChannel); + G_MainWin->keyboard->updateChannel(ch->guiChannel); return result; } @@ -75,10 +88,9 @@ int glue_loadChannel(SampleChannel *ch, const char *fname) Channel *glue_addChannel(int column, int type) { - Channel *ch = G_Mixer.addChannel(type); - gChannel *gch = mainWin->keyboard->addChannel(column, ch); - ch->guiChannel = gch; - glue_setChanVol(ch, 1.0, false); // false = not from gui click + Channel *ch = G_Mixer.addChannel(type); + geChannel *gch = G_MainWin->keyboard->addChannel(column, ch); + ch->guiChannel = gch; return ch; } @@ -88,12 +100,12 @@ Channel *glue_addChannel(int column, int type) void glue_deleteChannel(Channel *ch) { - recorder::clearChan(ch->index); + G_Recorder.clearChan(ch->index); #ifdef WITH_VST G_PluginHost.freeStack(PluginHost::CHANNEL, &G_Mixer.mutex_plugins, ch); #endif Fl::lock(); - mainWin->keyboard->deleteChannel(ch->guiChannel); + G_MainWin->keyboard->deleteChannel(ch->guiChannel); Fl::unlock(); G_Mixer.deleteChannel(ch); gu_closeAllSubwindows(); @@ -106,10 +118,13 @@ void glue_deleteChannel(Channel *ch) void glue_freeChannel(Channel *ch) { #ifdef WITH_VST + G_PluginHost.freeStack(PluginHost::CHANNEL, &G_Mixer.mutex_plugins, ch); + ch->guiChannel->fx->full = false; + #endif - mainWin->keyboard->freeChannel(ch->guiChannel); - recorder::clearChan(ch->index); + G_MainWin->keyboard->freeChannel(ch->guiChannel); + G_Recorder.clearChan(ch->index); ch->empty(); } @@ -117,14 +132,349 @@ void glue_freeChannel(Channel *ch) /* -------------------------------------------------------------------------- */ +void glue_toggleArm(Channel *ch, bool gui) +{ + ch->armed = !ch->armed; + if (!gui) + ch->guiChannel->arm->value(ch->armed); +} + + +/* -------------------------------------------------------------------------- */ + + int glue_cloneChannel(Channel *src) { Channel *ch = G_Mixer.addChannel(src->type); - gChannel *gch = mainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch); + geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch); ch->guiChannel = gch; ch->copy(src, &G_Mixer.mutex_plugins); - mainWin->keyboard->updateChannel(ch->guiChannel); + G_MainWin->keyboard->updateChannel(ch->guiChannel); return true; } + + +/* -------------------------------------------------------------------------- */ + + +void glue_setChanVol(Channel *ch, float v, bool gui) +{ + ch->volume = v; + + /* also update wave editor if it's shown */ + + gdEditor *editor = (gdEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR); + if (editor) { + glue_setVolEditor(editor, (SampleChannel*) ch, v, false); + Fl::lock(); + editor->volume->value(v); + Fl::unlock(); + } + + if (!gui) { + Fl::lock(); + ch->guiChannel->vol->value(v); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setPitch(gdEditor *win, SampleChannel *ch, float val, bool numeric) +{ + if (numeric) { + if (val <= 0.0f) + val = 0.1000f; + if (val > 4.0f) + val = 4.0000f; + if (win) + win->pitch->value(val); + } + + ch->setPitch(val); + + if (win) { + char buf[16]; + sprintf(buf, "%.4f", val); + Fl::lock(); + win->pitchNum->value(buf); + win->pitchNum->redraw(); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setPanning(gdEditor *win, SampleChannel *ch, float val) +{ + if (val < 1.0f) { + ch->panLeft = 1.0f; + ch->panRight= 0.0f + val; + + char buf[8]; + sprintf(buf, "%d L", (int) std::abs((ch->panRight * 100.0f) - 100)); + win->panNum->value(buf); + } + else if (val == 1.0f) { + ch->panLeft = 1.0f; + ch->panRight= 1.0f; + win->panNum->value("C"); + } + else { + ch->panLeft = 2.0f - val; + ch->panRight= 1.0f; + + char buf[8]; + sprintf(buf, "%d R", (int) std::abs((ch->panLeft * 100.0f) - 100)); + win->panNum->value(buf); + } + win->panNum->redraw(); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setMute(Channel *ch, bool gui) +{ + if (G_Recorder.active && G_Recorder.canRec(ch)) { + if (!ch->mute) + G_Recorder.startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame); + else + G_Recorder.stopOverdub(G_Mixer.actualFrame); + } + + ch->mute ? ch->unsetMute(false) : ch->setMute(false); + + if (!gui) { + Fl::lock(); + ch->guiChannel->mute->value(ch->mute); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setSoloOn(Channel *ch, bool gui) +{ + /* if there's no solo session, store mute configuration of all chans + * and start the session */ + + if (!__soloSession__) { + for (unsigned i=0; imute_s = och->mute; + } + __soloSession__ = true; + } + + ch->solo = !ch->solo; + ch->sendMidiLsolo(); + + /* mute all other channels and unmute this (if muted) */ + + for (unsigned i=0; isolo && !och->mute) { + och->setMute(false); + Fl::lock(); + och->guiChannel->mute->value(true); + Fl::unlock(); + } + } + + if (ch->mute) { + ch->unsetMute(false); + Fl::lock(); + ch->guiChannel->mute->value(false); + Fl::unlock(); + } + + if (!gui) { + Fl::lock(); + ch->guiChannel->solo->value(1); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setSoloOff(Channel *ch, bool gui) +{ + /* if this is uniqueSolo, stop solo session and restore mute status, + * else mute this */ + + if (mh_uniqueSolo(ch)) { + __soloSession__ = false; + for (unsigned i=0; imute_s) { + och->setMute(false); + Fl::lock(); + och->guiChannel->mute->value(true); + Fl::unlock(); + } + else { + och->unsetMute(false); + Fl::lock(); + och->guiChannel->mute->value(false); + Fl::unlock(); + } + och->mute_s = false; + } + } + else { + ch->setMute(false); + Fl::lock(); + ch->guiChannel->mute->value(true); + Fl::unlock(); + } + + ch->solo = !ch->solo; + ch->sendMidiLsolo(); + + if (!gui) { + Fl::lock(); + ch->guiChannel->solo->value(0); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, + bool recalc, bool check) +{ + if (check) { + if (e > ch->wave->size) + e = ch->wave->size; + if (b < 0) + b = 0; + if (b > ch->wave->size) + b = ch->wave->size-2; + if (b >= ch->end) + b = ch->begin; + if (e <= ch->begin) + e = ch->end; + } + + /* continue only if new values != old values */ + + if (b == ch->begin && e == ch->end) + return; + + /* print mono values */ + + char tmp[16]; + sprintf(tmp, "%d", b/2); + win->chanStart->value(tmp); + + tmp[0] = '\0'; + sprintf(tmp, "%d", e/2); + win->chanEnd->value(tmp); + + ch->setBegin(b); + ch->setEnd(e); + + /* Recalc is not needed when the user drags the bars directly over the + waveform */ + + if (recalc) { + win->waveTools->waveform->recalcPoints(); + win->waveTools->waveform->redraw(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric) +{ + if (numeric) { + if (val > 20.0f) + val = 20.0f; + else if (val < 0.0f) + val = 0.0f; + + float linear = pow(10, (val / 20)); // linear = 10^(dB/20) + + ch->boost = linear; + + char buf[10]; + sprintf(buf, "%.2f", val); + win->boostNum->value(buf); + win->boostNum->redraw(); + + win->boost->value(linear); + win->boost->redraw(); /// inutile + } + else { + ch->boost = val; + char buf[10]; + sprintf(buf, "%.2f", 20*log10(val)); + win->boostNum->value(buf); + win->boostNum->redraw(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, + bool numeric) +{ + if (numeric) { + if (val > 0.0f) + val = 0.0f; + else if (val < -60.0f) + val = -INFINITY; + + float linear = pow(10, (val / 20)); // linear = 10^(dB/20) + + ch->volume = linear; + + win->volume->value(linear); + win->volume->redraw(); + + char buf[10]; + if (val > -INFINITY) + sprintf(buf, "%.2f", val); + else + sprintf(buf, "-inf"); + win->volumeNum->value(buf); + win->volumeNum->redraw(); + + ch->guiChannel->vol->value(linear); + ch->guiChannel->vol->redraw(); + } + else { + ch->volume = val; + + float dbVal = 20 * log10(val); + char buf[10]; + if (dbVal > -INFINITY) + sprintf(buf, "%.2f", dbVal); + else + sprintf(buf, "-inf"); + + win->volumeNum->value(buf); + win->volumeNum->redraw(); + + ch->guiChannel->vol->value(val); + ch->guiChannel->vol->redraw(); + } +} diff --git a/src/glue/channel.h b/src/glue/channel.h index 2da2bf1..25523e0 100644 --- a/src/glue/channel.h +++ b/src/glue/channel.h @@ -32,10 +32,7 @@ #define GLUE_CHANNEL_H -#include "../core/patch.h" - - -using std::string; +#include /* addChannel @@ -46,7 +43,7 @@ class Channel *glue_addChannel(int column, int type); /* loadChannel * fill an existing channel with a wave. */ -int glue_loadChannel(class SampleChannel *ch, const char *fname); +int glue_loadChannel(class SampleChannel *ch, const std::string &fname); /* deleteChannel * Remove a channel from Mixer. */ @@ -60,8 +57,41 @@ void glue_freeChannel(class Channel *ch); /* cloneChannel * Make an exact copy of Channel *ch. */ - + int glue_cloneChannel(class Channel *ch); +/* toggle/set* + * Toggle or set several channel properties. If gui == true the signal comes + * from a manual interaction on the GUI, otherwise it's a MIDI/Jack/external + * signal. */ + +void glue_toggleArm(class Channel *ch, bool gui=true); +void glue_setChanVol(class Channel *ch, float v, bool gui=true); +void glue_setMute(class Channel *ch, bool gui=true); +void glue_setSoloOn (class Channel *ch, bool gui=true); +void glue_setSoloOff(class Channel *ch, bool gui=true); + +void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, + bool numeric); + +void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val); + +/* setBeginEndChannel + * sets start/end points in the sample editor. Recalc=false: don't recalc + * internal position. check=true: check the points' consistency */ + +void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, + int b, int e, bool recalc=false, bool check=true); + +void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, + bool numeric); + +/* setVolEditor + * handles the volume inside the SAMPLE EDITOR (not the main gui). The + * numeric flag tells if we want to handle the dial or the numeric input + * field. */ + +void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, + bool numeric); #endif diff --git a/src/glue/glue.cpp b/src/glue/glue.cpp deleted file mode 100644 index ff1670c..0000000 --- a/src/glue/glue.cpp +++ /dev/null @@ -1,972 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * glue - * Intermediate layer GUI <-> CORE. - * - * How to know if you need another glue_ function? Ask yourself if the - * new action will ever be called via MIDI or keyboard/mouse. If yes, - * put it here. - * - * ----------------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * -------------------------------------------------------------------------- */ - - -#include "../gui/elems/ge_waveform.h" -#include "../gui/elems/ge_mixed.h" -#include "../gui/elems/ge_channel.h" -#include "../gui/elems/ge_sampleChannel.h" -#include "../gui/elems/ge_waveTools.h" -#include "../gui/elems/ge_keyboard.h" -#include "../gui/dialogs/gd_mainWindow.h" -#include "../gui/dialogs/gd_editor.h" -#include "../gui/dialogs/gd_warnings.h" -#include "../utils/gui_utils.h" -#include "../utils/utils.h" -#include "../utils/log.h" -#include "../core/mixerHandler.h" -#include "../core/mixer.h" -#include "../core/recorder.h" -#include "../core/wave.h" -#include "../core/pluginHost.h" -#include "../core/channel.h" -#include "../core/sampleChannel.h" -#include "../core/midiChannel.h" -#include "../core/kernelMidi.h" -#include "../core/patch_DEPR_.h" -#include "../core/conf.h" -#include "glue.h" - - -extern gdMainWindow *mainWin; -extern Mixer G_Mixer; -extern Patch_DEPR_ G_Patch_DEPR_; -extern Conf G_Conf; -extern bool G_audio_status; -#ifdef WITH_VST -extern PluginHost G_PluginHost; -#endif - - -static bool __soloSession__ = false; - - -void glue_setBpm(const char *v1, const char *v2) -{ - char buf[6]; - float value = atof(v1) + (atof(v2)/10); - if (value < 20.0f) { - value = 20.0f; - sprintf(buf, "20.0"); - } - else - sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2); - - /* a value such as atof("120.1") will never be 120.1 but 120.0999999, - * because of the rounding error. So we pass the real "wrong" value to - * G_Mixer and we show the nice looking (but fake) one to the GUI. */ - - float old_bpm = G_Mixer.bpm; - G_Mixer.bpm = value; - G_Mixer.updateFrameBars(); - - /* inform recorder and actionEditor of the change */ - - recorder::updateBpm(old_bpm, value, G_Mixer.quanto); - gu_refreshActionEditor(); - - mainWin->timing->setBpm(buf); - gLog("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setBeats(int beats, int bars, bool expand) -{ - /* temp vars to store old data (they are necessary) */ - - int oldvalue = G_Mixer.beats; - unsigned oldfpb = G_Mixer.totalFrames; - - if (beats > MAX_BEATS) - G_Mixer.beats = MAX_BEATS; - else if (beats < 1) - G_Mixer.beats = 1; - else - G_Mixer.beats = beats; - - /* update bars - bars cannot be greate than beats and must be a sub - * multiple of beats. If not, approximation to the nearest (and greater) - * value available. */ - - if (bars > G_Mixer.beats) - G_Mixer.bars = G_Mixer.beats; - else if (bars <= 0) - G_Mixer.bars = 1; - else if (beats % bars != 0) { - G_Mixer.bars = bars + (beats % bars); - if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it) - G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars); - } - else - G_Mixer.bars = bars; - - G_Mixer.updateFrameBars(); - - /* update recorded actions */ - - if (expand) { - if (G_Mixer.beats > oldvalue) - recorder::expand(oldfpb, G_Mixer.totalFrames); - //else if (G_Mixer.beats < oldvalue) - // recorder::shrink(G_Mixer.totalFrames); - } - - mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); - gu_refreshActionEditor(); // in case the action editor is open -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startStopSeq(bool gui) -{ - G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startSeq(bool gui) -{ - G_Mixer.running = true; - - if (gui) { -#ifdef __linux__ - kernelAudio::jackStart(); -#endif - } - - if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { - kernelMidi::send(MIDI_START, -1, -1); - kernelMidi::send(MIDI_POSITION_PTR, 0, 0); - } - - if (gui) Fl::lock(); - mainWin->controller->updatePlay(1); - if (gui) Fl::unlock(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_stopSeq(bool gui) { - - mh_stopSequencer(); - - if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) - kernelMidi::send(MIDI_STOP, -1, -1); - -#ifdef __linux__ - if (gui) - kernelAudio::jackStop(); -#endif - - /* what to do if we stop the sequencer and some action recs are active? - * Deactivate the button and delete any 'rec on' status */ - - if (recorder::active) { - recorder::active = false; - if (gui) Fl::lock(); - mainWin->controller->updateRecAction(0); - if (gui) Fl::unlock(); - } - - /* if input recs are active (who knows why) we must deactivate them. - * One might stop the sequencer while an input rec is running. */ - - if (G_Mixer.chanInput != NULL) { - mh_stopInputRec(); - if (gui) Fl::lock(); - mainWin->controller->updateRecInput(0); - if (gui) Fl::unlock(); - } - - if (gui) Fl::lock(); - mainWin->controller->updatePlay(0); - if (gui) Fl::unlock(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_rewindSeq() { - mh_rewindSequencer(); - if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) - kernelMidi::send(MIDI_POSITION_PTR, 0, 0); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startStopActionRec() { - recorder::active ? glue_stopActionRec() : glue_startActionRec(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startActionRec() { - if (G_audio_status == false) - return; - if (!G_Mixer.running) - glue_startSeq(); // start the sequencer for convenience - recorder::active = true; - - Fl::lock(); - mainWin->controller->updateRecAction(1); - Fl::unlock(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_stopActionRec() { - - /* stop the recorder and sort new actions */ - - recorder::active = false; - recorder::sortActions(); - - for (unsigned i=0; itype == CHANNEL_SAMPLE) { - SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); - if (ch->hasActions) - ch->readActions = true; - else - ch->readActions = false; - mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); - } - - Fl::lock(); - mainWin->controller->updateRecAction(0); - Fl::unlock(); - - /* in case acton editor is on, refresh it */ - - gu_refreshActionEditor(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startStopReadingRecs(SampleChannel *ch, bool gui) { - if (ch->readActions) - glue_stopReadingRecs(ch, gui); - else - glue_startReadingRecs(ch, gui); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startReadingRecs(SampleChannel *ch, bool gui) { - if (G_Conf.treatRecsAsLoops) - ch->recStatus = REC_WAITING; - else - ch->setReadActions(true, G_Conf.recsStopOnChanHalt); - if (!gui) { - gSampleChannel *gch = (gSampleChannel*)ch->guiChannel; - if (gch->readActions) { // if button exists - Fl::lock(); - gch->readActions->value(1); - Fl::unlock(); - } - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_stopReadingRecs(SampleChannel *ch, bool gui) { - - /* if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put - * the channel in REC_ENDING status */ - - if (G_Conf.treatRecsAsLoops) - ch->recStatus = REC_ENDING; - else - ch->setReadActions(false, G_Conf.recsStopOnChanHalt); - if (!gui) { - gSampleChannel *gch = (gSampleChannel*)ch->guiChannel; - if (gch->readActions) { // if button exists - Fl::lock(); - gch->readActions->value(0); - Fl::unlock(); - } - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_quantize(int val) { - G_Mixer.quantize = val; - G_Mixer.updateQuanto(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setChanVol(Channel *ch, float v, bool gui) { - - ch->volume = v; - - /* also update wave editor if it's shown */ - - gdEditor *editor = (gdEditor*) gu_getSubwindow(mainWin, WID_SAMPLE_EDITOR); - if (editor) { - glue_setVolEditor(editor, (SampleChannel*) ch, v, false); - Fl::lock(); - editor->volume->value(v); - Fl::unlock(); - } - - if (!gui) { - Fl::lock(); - ch->guiChannel->vol->value(v); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setOutVol(float v, bool gui) { - G_Mixer.outVol = v; - if (!gui) { - Fl::lock(); - mainWin->inOut->setOutVol(v); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setInVol(float v, bool gui) -{ - G_Mixer.inVol = v; - if (!gui) { - Fl::lock(); - mainWin->inOut->setInVol(v); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_clearAllSamples() -{ - G_Mixer.running = false; - for (unsigned i=0; iempty(); - G_Mixer.channels.at(i)->guiChannel->reset(); - } - recorder::init(); - return; -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_clearAllRecs() -{ - recorder::init(); - gu_updateControls(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_resetToInitState(bool resetGui, bool createColumns) -{ - G_Patch_DEPR_.setDefault(); - G_Mixer.close(); - G_Mixer.init(); - recorder::init(); -#ifdef WITH_VST - G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins); -#endif - - mainWin->keyboard->clear(); - if (createColumns) - mainWin->keyboard->init(); - - if (resetGui) - gu_updateControls(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startStopMetronome(bool gui) -{ - G_Mixer.metronome = !G_Mixer.metronome; - if (!gui) { - Fl::lock(); - mainWin->controller->updateMetronome(G_Mixer.metronome); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, bool recalc, bool check) -{ - if (check) { - if (e > ch->wave->size) - e = ch->wave->size; - if (b < 0) - b = 0; - if (b > ch->wave->size) - b = ch->wave->size-2; - if (b >= ch->end) - b = ch->begin; - if (e <= ch->begin) - e = ch->end; - } - - /* continue only if new values != old values */ - - if (b == ch->begin && e == ch->end) - return; - - /* print mono values */ - - char tmp[16]; - sprintf(tmp, "%d", b/2); - win->chanStart->value(tmp); - - tmp[0] = '\0'; - sprintf(tmp, "%d", e/2); - win->chanEnd->value(tmp); - - ch->setBegin(b); - ch->setEnd(e); - - /* recalc is not needed when the user drags the bars directly over the waveform */ - - if (recalc) { - win->waveTools->waveform->recalcPoints(); // importante, altrimenti non si vedono - win->waveTools->waveform->redraw(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric) -{ - if (numeric) { - if (val > 20.0f) - val = 20.0f; - else if (val < 0.0f) - val = 0.0f; - - float linear = pow(10, (val / 20)); // linear = 10^(dB/20) - - ch->boost = linear; - - char buf[10]; - sprintf(buf, "%.2f", val); - win->boostNum->value(buf); - win->boostNum->redraw(); - - win->boost->value(linear); - win->boost->redraw(); /// inutile - } - else { - ch->boost = val; - char buf[10]; - sprintf(buf, "%.2f", 20*log10(val)); - win->boostNum->value(buf); - win->boostNum->redraw(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, bool numeric) -{ - if (numeric) { - if (val > 0.0f) - val = 0.0f; - else if (val < -60.0f) - val = -INFINITY; - - float linear = pow(10, (val / 20)); // linear = 10^(dB/20) - - ch->volume = linear; - - win->volume->value(linear); - win->volume->redraw(); - - char buf[10]; - if (val > -INFINITY) - sprintf(buf, "%.2f", val); - else - sprintf(buf, "-inf"); - win->volumeNum->value(buf); - win->volumeNum->redraw(); - - ch->guiChannel->vol->value(linear); - ch->guiChannel->vol->redraw(); - } - else { - ch->volume = val; - - float dbVal = 20 * log10(val); - char buf[10]; - if (dbVal > -INFINITY) - sprintf(buf, "%.2f", dbVal); - else - sprintf(buf, "-inf"); - - win->volumeNum->value(buf); - win->volumeNum->redraw(); - - ch->guiChannel->vol->value(val); - ch->guiChannel->vol->redraw(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setMute(Channel *ch, bool gui) -{ - if (recorder::active && recorder::canRec(ch)) { - if (!ch->mute) - recorder::startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame); - else - recorder::stopOverdub(G_Mixer.actualFrame); - } - - ch->mute ? ch->unsetMute(false) : ch->setMute(false); - - if (!gui) { - Fl::lock(); - ch->guiChannel->mute->value(ch->mute); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setSoloOn(Channel *ch, bool gui) -{ - /* if there's no solo session, store mute configuration of all chans - * and start the session */ - - if (!__soloSession__) { - for (unsigned i=0; imute_s = och->mute; - } - __soloSession__ = true; - } - - ch->solo = !ch->solo; - ch->sendMidiLsolo(); - - /* mute all other channels and unmute this (if muted) */ - - for (unsigned i=0; isolo && !och->mute) { - och->setMute(false); - Fl::lock(); - och->guiChannel->mute->value(true); - Fl::unlock(); - } - } - - if (ch->mute) { - ch->unsetMute(false); - Fl::lock(); - ch->guiChannel->mute->value(false); - Fl::unlock(); - } - - if (!gui) { - Fl::lock(); - ch->guiChannel->solo->value(1); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setSoloOff(Channel *ch, bool gui) -{ - /* if this is uniqueSolo, stop solo session and restore mute status, - * else mute this */ - - if (mh_uniqueSolo(ch)) { - __soloSession__ = false; - for (unsigned i=0; imute_s) { - och->setMute(false); - Fl::lock(); - och->guiChannel->mute->value(true); - Fl::unlock(); - } - else { - och->unsetMute(false); - Fl::lock(); - och->guiChannel->mute->value(false); - Fl::unlock(); - } - och->mute_s = false; - } - } - else { - ch->setMute(false); - Fl::lock(); - ch->guiChannel->mute->value(true); - Fl::unlock(); - } - - ch->solo = !ch->solo; - ch->sendMidiLsolo(); - - if (!gui) { - Fl::lock(); - ch->guiChannel->solo->value(0); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val) -{ - if (val < 1.0f) { - ch->panLeft = 1.0f; - ch->panRight= 0.0f + val; - - char buf[8]; - sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100)); - win->panNum->value(buf); - } - else if (val == 1.0f) { - ch->panLeft = 1.0f; - ch->panRight= 1.0f; - win->panNum->value("C"); - } - else { - ch->panLeft = 2.0f - val; - ch->panRight= 1.0f; - - char buf[8]; - sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100)); - win->panNum->value(buf); - } - win->panNum->redraw(); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_startStopInputRec(bool gui, bool alert) -{ - if (G_Mixer.chanInput == NULL) { - if (!glue_startInputRec(gui)) { - if (alert) gdAlert("No channels available for recording."); - else gLog("[glue] no channels available for recording\n"); - } - } - else - glue_stopInputRec(gui); -} - - -/* -------------------------------------------------------------------------- */ - - -int glue_startInputRec(bool gui) -{ - if (G_audio_status == false) - return -1; - - SampleChannel *ch = mh_startInputRec(); - if (ch == NULL) { // no chans available - Fl::lock(); - mainWin->controller->updateRecInput(0); - Fl::unlock(); - return 0; - } - - if (!G_Mixer.running) { - glue_startSeq(); - Fl::lock(); - mainWin->controller->updatePlay(1); - Fl::unlock(); - } - - glue_setChanVol(ch, 1.0f, false); // false = not from gui click - - ch->guiChannel->mainButton->label(ch->wave->name.c_str()); - - if (!gui) { - Fl::lock(); - mainWin->controller->updateRecInput(1); - Fl::unlock(); - } - - return 1; - -} - - -/* -------------------------------------------------------------------------- */ - - -int glue_stopInputRec(bool gui) -{ - SampleChannel *ch = mh_stopInputRec(); - - if (ch->mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT)) - ch->start(0, true, G_Mixer.quantize, G_Mixer.running); // on frame 0: user-generated event - - if (!gui) { - Fl::lock(); - mainWin->controller->updateRecInput(0); - Fl::unlock(); - } - - return 1; -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_keyPress(Channel *ch, bool ctrl, bool shift) -{ - if (ch->type == CHANNEL_SAMPLE) - glue_keyPress((SampleChannel*)ch, ctrl, shift); - else - glue_keyPress((MidiChannel*)ch, ctrl, shift); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_keyRelease(Channel *ch, bool ctrl, bool shift) -{ - if (ch->type == CHANNEL_SAMPLE) - glue_keyRelease((SampleChannel*)ch, ctrl, shift); -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift) -{ - if (ctrl) - glue_setMute(ch); - else - if (shift) - ch->kill(0); // on frame 0: user-generated event - else - ch->start(0, true, G_Mixer.quantize, G_Mixer.running); // on frame 0: user-generated event -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift) -{ - /* case CTRL */ - - if (ctrl) - glue_setMute(ch); - - /* case SHIFT - * - * action recording on: - * if seq is playing, rec a killchan - * action recording off: - * if chan has recorded events: - * | if seq is playing OR channel 'c' is stopped, de/activate recs - * | else kill chan - * else kill chan */ - - else - if (shift) { - if (recorder::active) { - if (G_Mixer.running) { - ch->kill(0); // on frame 0: user-generated event - if (recorder::canRec(ch) && !(ch->mode & LOOP_ANY)) // don't record killChan actions for LOOP channels - recorder::rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame); - } - } - else { - if (ch->hasActions) { - if (G_Mixer.running || ch->status == STATUS_OFF) - ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch); - else - ch->kill(0); // on frame 0: user-generated event - } - else - ch->kill(0); // on frame 0: user-generated event - } - } - - /* case no modifier */ - - else { - - /* record now if the quantizer is off, otherwise let mixer to handle it - * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are - * meaningless for loop modes */ - - if (G_Mixer.quantize == 0 && - recorder::canRec(ch) && - !(ch->mode & LOOP_ANY)) - { - if (ch->mode == SINGLE_PRESS) - recorder::startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame); - else - recorder::rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame); - } - - ch->start(0, true, G_Mixer.quantize, G_Mixer.running); // on frame 0: user-generated event - } - - /* the GUI update is done by gui_refresh() */ -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift) -{ - if (!ctrl && !shift) { - ch->stop(); - - /* record a key release only if channel is single_press. For any - * other mode the KEY REL is meaningless. */ - - if (ch->mode == SINGLE_PRESS && recorder::canRec(ch)) - recorder::stopOverdub(G_Mixer.actualFrame); - } - - /* the GUI update is done by gui_refresh() */ - -} - - -/* -------------------------------------------------------------------------- */ - - -void glue_setPitch(class gdEditor *win, SampleChannel *ch, float val, bool numeric) -{ - if (numeric) { - if (val <= 0.0f) - val = 0.1000f; - if (val > 4.0f) - val = 4.0000f; - if (win) - win->pitch->value(val); - } - - ch->setPitch(val); - - if (win) { - char buf[16]; - sprintf(buf, "%.4f", val); - Fl::lock(); - win->pitchNum->value(buf); - win->pitchNum->redraw(); - Fl::unlock(); - } -} - - -/* -------------------------------------------------------------------------- */ - - -/* never expand or shrink recordings (last param of setBeats = false): - * this is live manipulation */ - -void glue_beatsMultiply() -{ - glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false); -} - -void glue_beatsDivide() -{ - glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false); -} diff --git a/src/glue/glue.h b/src/glue/glue.h deleted file mode 100644 index ef7076f..0000000 --- a/src/glue/glue.h +++ /dev/null @@ -1,148 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * glue - * Intermediate layer GUI <-> CORE. - * - * How to know if you need another glue_ function? Ask yourself if the - * new action will ever be called via MIDI or keyboard/mouse. If yes, - * put it here. - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual - * - * This file is part of Giada - Your Hardcore Loopmachine. - * - * Giada - Your Hardcore Loopmachine is free software: you can - * redistribute it and/or modify it under the terms of the GNU General - * Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * Giada - Your Hardcore Loopmachine is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Giada - Your Hardcore Loopmachine. If not, see - * . - * - * ------------------------------------------------------------------ */ - - -#ifndef GLUE_H -#define GLUE_H - - -/* keyPress / keyRelease - * handle the key pressure, either via mouse/keyboard or MIDI. If gui - * is true it means that the event comes from the main window (mouse, - * keyb or MIDI), otherwise the event comes from the action recorder. */ - -void glue_keyPress (class Channel *ch, bool ctrl=0, bool shift=0); -void glue_keyPress (class SampleChannel *ch, bool ctrl=0, bool shift=0); -void glue_keyPress (class MidiChannel *ch, bool ctrl=0, bool shift=0); -void glue_keyRelease(class Channel *ch, bool ctrl=0, bool shift=0); -void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0); - -void glue_setBpm(const char *v1, const char *v2); -void glue_setBeats(int beats, int bars, bool expand); - -/* start, stop, rewind sequencer - * if gui == true the signal comes from an internal interaction on the - * GUI, otherwise it's a MIDI/Jack/external signal. */ - -void glue_startStopSeq(bool gui=true); -void glue_startSeq (bool gui=true); -void glue_stopSeq (bool gui=true); -void glue_rewindSeq (); - -/* start/stopActionRec - * handle the action recording. */ - -void glue_startStopActionRec(); -void glue_startActionRec(); -void glue_stopActionRec(); - -/* start/stopInputRec - * handle the input recording (take). If gui == true the signal comes - * from an internal interaction on the GUI, otherwise it's a - * MIDI/Jack/external signal. Alert displays or not the popup message - * if there are no available channels. */ - -void glue_startStopInputRec(bool gui=true, bool alert=true); -int glue_startInputRec (bool gui=true); -int glue_stopInputRec (bool gui=true); - -/* start/stopReadingRecs - * handle the 'R' button. If gui == true the signal comes from an - * internal interaction on the GUI, otherwise it's a MIDI/Jack/external - * signal. */ - -void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true); -void glue_startReadingRecs (class SampleChannel *ch, bool gui=true); -void glue_stopReadingRecs (class SampleChannel *ch, bool gui=true); - -void glue_quantize(int val); - -void glue_setChanVol(class Channel *ch, float v, bool gui=true); -void glue_setOutVol (float v, bool gui=true); -void glue_setInVol (float v, bool gui=true); - -void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val); - -void glue_clearAllSamples(); -void glue_clearAllRecs(); - -/* resetToInitState - * reset Giada to init state. If resetGui also refresh all widgets. If - * createColumns also build initial empty columns. */ - -void glue_resetToInitState(bool resetGui=true, bool createColumns=true); - -void glue_startStopMetronome(bool gui=true); - -/* setBeginEndChannel - * sets start/end points in the sample editor. - * Recalc=false: don't recalc internal position - * check=true: check the points' consistency */ - -/** FIXME - nobody will call this via MIDI/keyb/mouse! */ -void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, int b, int e, - bool recalc=false, bool check=true); - -/** FIXME - nobody will call this via MIDI/keyb/mouse! */ -void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); - -void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); - -/* setVolEditor - * handles the volume inside the SAMPLE EDITOR (not the main gui). The - * numeric flag tells if we want to handle the dial or the numeric input - * field. */ - - /** FIXME - nobody will call this via MIDI/keyb/mouse! */ -void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); - -/* mute - * set mute on or off. If gui == true the signal comes from an internal - * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */ - -void glue_setMute(class Channel *ch, bool gui=true); - -/* solo on/off - * set solo on and off. If gui == true the signal comes from an internal - * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */ - -void glue_setSoloOn (class Channel *ch, bool gui=true); -void glue_setSoloOff(class Channel *ch, bool gui=true); - -/* beatsDivide/Multiply - * shrinks or enlarges the number of beats by 2. */ - -void glue_beatsMultiply(); -void glue_beatsDivide(); - -#endif diff --git a/src/glue/io.cpp b/src/glue/io.cpp new file mode 100644 index 0000000..bdc932e --- /dev/null +++ b/src/glue/io.cpp @@ -0,0 +1,327 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * How to know if you need another glue_ function? Ask yourself if the + * new action will ever be called via MIDI or keyboard/mouse. If yes, + * put it here. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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 "../gui/dialogs/gd_mainWindow.h" +#include "../gui/dialogs/gd_warnings.h" +#include "../gui/elems/ge_keyboard.h" +#include "../gui/elems/channel.h" +#include "../gui/elems/sampleChannel.h" +#include "../utils/gui.h" +#include "../utils/log.h" +#include "../core/recorder.h" +#include "../core/mixer.h" +#include "../core/mixerHandler.h" +#include "../core/wave.h" +#include "../core/channel.h" +#include "../core/sampleChannel.h" +#include "../core/midiChannel.h" +#include "main.h" +#include "channel.h" +#include "io.h" + + +extern Recorder G_Recorder; +extern bool G_audio_status; +extern Mixer G_Mixer; +extern gdMainWindow *G_MainWin; + + +void glue_keyPress(Channel *ch, bool ctrl, bool shift) +{ + if (ch->type == CHANNEL_SAMPLE) + glue_keyPress((SampleChannel*)ch, ctrl, shift); + else + glue_keyPress((MidiChannel*)ch, ctrl, shift); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_keyRelease(Channel *ch, bool ctrl, bool shift) +{ + if (ch->type == CHANNEL_SAMPLE) + glue_keyRelease((SampleChannel*)ch, ctrl, shift); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift) +{ + if (ctrl) + glue_setMute(ch); + else + if (shift) + ch->kill(0); // on frame 0: user-generated event + else + ch->start(0, true, G_Mixer.quantize, G_Mixer.running, false, true); // on frame 0: user-generated event +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift) +{ + /* case CTRL */ + + if (ctrl) + glue_setMute(ch); + + /* case SHIFT + * + * action recording on: + * if seq is playing, rec a killchan + * action recording off: + * if chan has recorded events: + * | if seq is playing OR channel 'c' is stopped, de/activate recs + * | else kill chan + * else kill chan */ + + else + if (shift) { + if (G_Recorder.active) { + if (G_Mixer.running) { + ch->kill(0); // on frame 0: user-generated event + if (G_Recorder.canRec(ch) && !(ch->mode & LOOP_ANY)) // don't record killChan actions for LOOP channels + G_Recorder.rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame); + } + } + else { + if (ch->hasActions) { + if (G_Mixer.running || ch->status == STATUS_OFF) + ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch); + else + ch->kill(0); // on frame 0: user-generated event + } + else + ch->kill(0); // on frame 0: user-generated event + } + } + else { /* case no modifier */ + + /* record now if the quantizer is off, otherwise let mixer to handle it + * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are + * meaningless for loop modes */ + + if (G_Mixer.quantize == 0 && + G_Recorder.canRec(ch) && + !(ch->mode & LOOP_ANY)) + { + if (ch->mode == SINGLE_PRESS) + G_Recorder.startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame); + else { + G_Recorder.rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame); + + /* Why return here? You record an action (as done on line 148) and then + you call ch->start (line 165): Mixer, which is on another thread, reads + your newly recorded action if you have readActions == true, and then + ch->start kicks in right after it (as done on line 165). + The result: Mixer plays the channel (due to the new action) but ch->start + kills it right away (because the sample is playing). Fix: call ch->start + only if you are not recording anything, i.e. let Mixer play it. */ + + if (ch->readActions) + return; + } + } + + /* This is a user-generated event, so it's on frame 0 */ + + ch->start(0, true, G_Mixer.quantize, G_Mixer.running, false, true); + } + + /* the GUI update is done by gui_refresh() */ +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift) +{ + if (ctrl || shift) + return; + + ch->stop(); + + /* record a key release only if channel is single_press. For any + * other mode the KEY REL is meaningless. */ + + if (ch->mode == SINGLE_PRESS && G_Recorder.canRec(ch)) + G_Recorder.stopOverdub(G_Mixer.actualFrame); + + /* the GUI update is done by gui_refresh() */ + +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startStopActionRec(bool gui) +{ + G_Recorder.active ? glue_stopActionRec(gui) : glue_startActionRec(gui); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startActionRec(bool gui) +{ + if (G_audio_status == false) + return; + + G_Recorder.active = true; + + if (!G_Mixer.running) + glue_startSeq(false); // update gui ayway + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updateRecAction(1); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_stopActionRec(bool gui) +{ + /* stop the recorder and sort new actions */ + + G_Recorder.active = false; + G_Recorder.sortActions(); + + for (unsigned i=0; itype == CHANNEL_MIDI) + continue; + SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)ch->guiChannel); + if (!ch->readActions && ch->hasActions) + glue_startReadingRecs(ch, false); + } + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updateRecAction(0); + Fl::unlock(); + } + + gu_refreshActionEditor(); // in case it's open +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startStopInputRec(bool gui) +{ + if (G_Mixer.recording) + glue_stopInputRec(gui); + else + if (!glue_startInputRec(gui)) + gdAlert("No channels armed/available for audio recording."); +} + + +/* -------------------------------------------------------------------------- */ + + +int glue_startInputRec(bool gui) +{ + if (G_audio_status == false) + return false; + + if (!mh_startInputRec()) { + Fl::lock(); + G_MainWin->controller->updateRecInput(0); // set it off, anyway + Fl::unlock(); + return false; + } + + if (!G_Mixer.running) + glue_startSeq(false); // update gui anyway + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updateRecInput(1); + Fl::unlock(); + } + + /* Update sample name inside sample channels' main button. This is useless for + midi channel, but let's do it anyway. */ + + for (unsigned i=0; iguiChannel->update(); + + return true; +} + + +/* -------------------------------------------------------------------------- */ + + +int glue_stopInputRec(bool gui) +{ + mh_stopInputRec(); + + /* Start all sample channels in loop mode that were armed, i.e. that were + recording stuff and not yet in play. They are also started in force mode, i.e. + they must start playing right away at the current frame, not at the next first + beat. */ + + for (unsigned i=0; itype == CHANNEL_MIDI) + continue; + SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); + if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->armed) + ch->start(G_Mixer.actualFrame, true, G_Mixer.quantize, G_Mixer.running, true, true); + } + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updateRecInput(0); + Fl::unlock(); + } + + return 1; +} diff --git a/src/glue/io.h b/src/glue/io.h new file mode 100644 index 0000000..b56160f --- /dev/null +++ b/src/glue/io.h @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * How to know if you need another glue_ function? Ask yourself if the + * new action will ever be called via MIDI or keyboard/mouse. If yes, + * put it here. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef GLUE_IO_H +#define GLUE_IO_H + + +/* keyPress / keyRelease + * handle the key pressure, either via mouse/keyboard or MIDI. If gui + * is true it means that the event comes from the main window (mouse, + * keyb or MIDI), otherwise the event comes from the action recorder. */ + +void glue_keyPress (class Channel *ch, bool ctrl=0, bool shift=0); +void glue_keyPress (class SampleChannel *ch, bool ctrl=0, bool shift=0); +void glue_keyPress (class MidiChannel *ch, bool ctrl=0, bool shift=0); +void glue_keyRelease(class Channel *ch, bool ctrl=0, bool shift=0); +void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0); + +/* start/stopActionRec +Handles the action recording. If gui == true the signal comes from an user +interaction, otherwise it's a MIDI/Jack/external signal. */ + +void glue_startStopActionRec(bool gui=true); +void glue_startActionRec(bool gui=true); +void glue_stopActionRec(bool gui=true); + +/* start/stopInputRec +Handles the input recording (take). If gui == true the signal comes from an +internal interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */ + +void glue_startStopInputRec(bool gui=true); +int glue_startInputRec (bool gui=true); +int glue_stopInputRec (bool gui=true); + + +#endif diff --git a/src/glue/main.cpp b/src/glue/main.cpp new file mode 100644 index 0000000..4c3638f --- /dev/null +++ b/src/glue/main.cpp @@ -0,0 +1,421 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * How to know if you need another glue_ function? Ask yourself if the + * new action will ever be called via MIDI or keyboard/mouse. If yes, + * put it here. + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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 "../gui/elems/ge_waveform.h" +#include "../gui/elems/ge_mixed.h" +#include "../gui/elems/channel.h" +#include "../gui/elems/sampleChannel.h" +#include "../gui/elems/ge_waveTools.h" +#include "../gui/elems/ge_keyboard.h" +#include "../gui/dialogs/gd_mainWindow.h" +#include "../gui/dialogs/gd_editor.h" +#include "../gui/dialogs/gd_warnings.h" +#include "../utils/gui.h" +#include "../utils/fs.h" +#include "../utils/log.h" +#include "../core/mixerHandler.h" +#include "../core/mixer.h" +#include "../core/recorder.h" +#include "../core/wave.h" +#include "../core/pluginHost.h" +#include "../core/channel.h" +#include "../core/sampleChannel.h" +#include "../core/midiChannel.h" +#include "../core/kernelMidi.h" +#include "../core/patch_DEPR_.h" +#include "../core/conf.h" +#include "main.h" + + +extern gdMainWindow *G_MainWin; +extern Mixer G_Mixer; +extern Recorder G_Recorder; +extern KernelAudio G_KernelAudio; +extern KernelMidi G_KernelMidi; +extern Patch_DEPR_ G_Patch_DEPR_; +extern Conf G_Conf; +extern bool G_audio_status; +#ifdef WITH_VST +extern PluginHost G_PluginHost; +#endif + + +void glue_setBpm(const char *v1, const char *v2) +{ + char buf[6]; + float value = atof(v1) + (atof(v2)/10); + if (value < 20.0f) { + value = 20.0f; + sprintf(buf, "20.0"); + } + else + sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2); + + /* a value such as atof("120.1") will never be 120.1 but 120.0999999, + * because of the rounding error. So we pass the real "wrong" value to + * G_Mixer and we show the nice looking (but fake) one to the GUI. */ + + float old_bpm = G_Mixer.bpm; + G_Mixer.bpm = value; + G_Mixer.updateFrameBars(); + + /* inform recorder and actionEditor of the change */ + + G_Recorder.updateBpm(old_bpm, value, G_Mixer.quanto); + gu_refreshActionEditor(); + + G_MainWin->timing->setBpm(buf); + gu_log("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setBeats(int beats, int bars, bool expand) +{ + /* temp vars to store old data (they are necessary) */ + + int oldvalue = G_Mixer.beats; + unsigned oldfpb = G_Mixer.totalFrames; + + if (beats > MAX_BEATS) + G_Mixer.beats = MAX_BEATS; + else if (beats < 1) + G_Mixer.beats = 1; + else + G_Mixer.beats = beats; + + /* update bars - bars cannot be greate than beats and must be a sub + * multiple of beats. If not, approximation to the nearest (and greater) + * value available. */ + + if (bars > G_Mixer.beats) + G_Mixer.bars = G_Mixer.beats; + else if (bars <= 0) + G_Mixer.bars = 1; + else if (beats % bars != 0) { + G_Mixer.bars = bars + (beats % bars); + if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it) + G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars); + } + else + G_Mixer.bars = bars; + + G_Mixer.updateFrameBars(); + + /* update recorded actions */ + + if (expand) { + if (G_Mixer.beats > oldvalue) + G_Recorder.expand(oldfpb, G_Mixer.totalFrames); + //else if (G_Mixer.beats < oldvalue) + // G_Recorder.shrink(G_Mixer.totalFrames); + } + + G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); + gu_refreshActionEditor(); // in case the action editor is open +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startStopSeq(bool gui) +{ + G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startSeq(bool gui) +{ + G_Mixer.running = true; + + if (gui) { +#ifdef __linux__ + G_KernelAudio.jackStart(); +#endif + } + + if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { + G_KernelMidi.send(MIDI_START, -1, -1); + G_KernelMidi.send(MIDI_POSITION_PTR, 0, 0); + } + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updatePlay(1); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_stopSeq(bool gui) +{ + mh_stopSequencer(); + + if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) + G_KernelMidi.send(MIDI_STOP, -1, -1); + +#ifdef __linux__ + if (gui) + G_KernelAudio.jackStop(); +#endif + + /* what to do if we stop the sequencer and some action recs are active? + * Deactivate the button and delete any 'rec on' status */ + + if (G_Recorder.active) { + G_Recorder.active = false; + Fl::lock(); + G_MainWin->controller->updateRecAction(0); + Fl::unlock(); + } + + /* if input recs are active (who knows why) we must deactivate them. + * One might stop the sequencer while an input rec is running. */ + + if (G_Mixer.recording) { + mh_stopInputRec(); + Fl::lock(); + G_MainWin->controller->updateRecInput(0); + Fl::unlock(); + } + + if (!gui) { + Fl::lock(); + G_MainWin->controller->updatePlay(0); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_rewindSeq() +{ + mh_rewindSequencer(); + if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) + G_KernelMidi.send(MIDI_POSITION_PTR, 0, 0); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startStopReadingRecs(SampleChannel *ch, bool gui) +{ + /* When you call glue_startReadingRecs with G_Conf.treatRecsAsLoops, the + member value ch->readActions actually is not set to true immediately, because + the channel is in wait mode (REC_WAITING). ch->readActions will become true on + the next first beat. So a 'stop rec' command should occur also when + ch->readActions is false but the channel is in wait mode; this check will + handle the case of when you press 'R', the channel goes into REC_WAITING and + then you press 'R' again to undo the status. */ + + if (ch->readActions || (!ch->readActions && ch->recStatus == REC_WAITING)) + glue_stopReadingRecs(ch, gui); + else + glue_startReadingRecs(ch, gui); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startReadingRecs(SampleChannel *ch, bool gui) +{ + if (G_Conf.treatRecsAsLoops) + ch->recStatus = REC_WAITING; + else + ch->setReadActions(true, G_Conf.recsStopOnChanHalt); + if (!gui) { + Fl::lock(); + ((geSampleChannel*)ch->guiChannel)->readActions->value(1); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_stopReadingRecs(SampleChannel *ch, bool gui) +{ + /* First of all, if the mixer is not running just stop and disable everything. + Then if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put the + channel in REC_ENDING status. */ + + if (!G_Mixer.running) { + ch->recStatus = REC_STOPPED; + ch->readActions = false; + } + else + if (G_Conf.treatRecsAsLoops) + ch->recStatus = REC_ENDING; + else + ch->setReadActions(false, G_Conf.recsStopOnChanHalt); + + if (!gui) { + Fl::lock(); + ((geSampleChannel*)ch->guiChannel)->readActions->value(0); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_quantize(int val) +{ + G_Mixer.quantize = val; + G_Mixer.updateQuanto(); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setOutVol(float v, bool gui) +{ + G_Mixer.outVol = v; + if (!gui) { + Fl::lock(); + G_MainWin->inOut->setOutVol(v); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_setInVol(float v, bool gui) +{ + G_Mixer.inVol = v; + if (!gui) { + Fl::lock(); + G_MainWin->inOut->setInVol(v); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_clearAllSamples() +{ + G_Mixer.running = false; + for (unsigned i=0; iempty(); + G_Mixer.channels.at(i)->guiChannel->reset(); + } + G_Recorder.init(); + return; +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_clearAllRecs() +{ + G_Recorder.init(); + gu_updateControls(); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_resetToInitState(bool resetGui, bool createColumns) +{ + G_Patch_DEPR_.setDefault(); + G_Mixer.close(); + G_Mixer.init(); + G_Recorder.init(); +#ifdef WITH_VST + G_PluginHost.freeAllStacks(&G_Mixer.channels, &G_Mixer.mutex_plugins); +#endif + + G_MainWin->keyboard->clear(); + if (createColumns) + G_MainWin->keyboard->init(); + + gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME); + + if (resetGui) + gu_updateControls(); +} + + +/* -------------------------------------------------------------------------- */ + + +void glue_startStopMetronome(bool gui) +{ + G_Mixer.metronome = !G_Mixer.metronome; + if (!gui) { + Fl::lock(); + G_MainWin->controller->updateMetronome(G_Mixer.metronome); + Fl::unlock(); + } +} + + +/* -------------------------------------------------------------------------- */ + + +/* never expand or shrink recordings (last param of setBeats = false): + * this is live manipulation */ + +void glue_beatsMultiply() +{ + glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false); +} + +void glue_beatsDivide() +{ + glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false); +} diff --git a/src/glue/main.h b/src/glue/main.h new file mode 100644 index 0000000..422f422 --- /dev/null +++ b/src/glue/main.h @@ -0,0 +1,81 @@ +/* --------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * glue + * Intermediate layer GUI <-> CORE. + * + * How to know if you need another glue_ function? Ask yourself if the + * new action will ever be called via MIDI or keyboard/mouse. If yes, + * put it here. + * + * --------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual + * + * This file is part of Giada - Your Hardcore Loopmachine. + * + * Giada - Your Hardcore Loopmachine is free software: you can + * redistribute it and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * Giada - Your Hardcore Loopmachine is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Giada - Your Hardcore Loopmachine. If not, see + * . + * + * ------------------------------------------------------------------ */ + + +#ifndef GLUE_H +#define GLUE_H + + +void glue_setBpm(const char *v1, const char *v2); +void glue_setBeats(int beats, int bars, bool expand); + +/* start, stop, rewind sequencer +If gui == true the signal comes from an user interaction on the GUI, +otherwise it's a MIDI/Jack/external signal. */ + +void glue_startStopSeq(bool gui=true); +void glue_startSeq (bool gui=true); +void glue_stopSeq (bool gui=true); +void glue_rewindSeq (); + +/* start/stopReadingRecs +Handles the 'R' button. If gui == true the signal comes from an user interaction +on the GUI, otherwise it's a MIDI/Jack/external signal. */ + +void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true); +void glue_startReadingRecs (class SampleChannel *ch, bool gui=true); +void glue_stopReadingRecs (class SampleChannel *ch, bool gui=true); + +void glue_quantize(int val); + +void glue_setOutVol (float v, bool gui=true); +void glue_setInVol (float v, bool gui=true); + +void glue_clearAllSamples(); +void glue_clearAllRecs(); + +/* resetToInitState + * reset Giada to init state. If resetGui also refresh all widgets. If + * createColumns also build initial empty columns. */ + +void glue_resetToInitState(bool resetGui=true, bool createColumns=true); + +void glue_startStopMetronome(bool gui=true); + +/* beatsDivide/Multiply + * shrinks or enlarges the number of beats by 2. */ + +void glue_beatsMultiply(); +void glue_beatsDivide(); + +#endif diff --git a/src/glue/storage.cpp b/src/glue/storage.cpp index d517736..41924d9 100644 --- a/src/glue/storage.cpp +++ b/src/glue/storage.cpp @@ -44,17 +44,20 @@ #include "../core/sampleChannel.h" #include "../core/midiChannel.h" #include "../core/wave.h" -#include "../utils/gui_utils.h" -#include "glue.h" // TODO - remove, used only for DEPR calls +#include "../utils/gui.h" +#include "../utils/log.h" +#include "main.h" // TODO - remove, used only for DEPR calls #include "channel.h" #include "storage.h" using std::string; +using std::vector; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; extern Mixer G_Mixer; +extern Recorder G_Recorder; extern Patch G_Patch; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; // TODO - remove, used only for DEPR calls @@ -87,8 +90,8 @@ static void __glue_fillPatchGlobalsPlugins__(vector *host, vectorkeyboard->getTotalColumns(); i++) { - gColumn *gCol = mainWin->keyboard->getColumn(i); + for (unsigned i=0; ikeyboard->getTotalColumns(); i++) { + gColumn *gCol = G_MainWin->keyboard->getColumn(i); Patch::column_t pCol; pCol.index = gCol->getIndex(); pCol.width = gCol->w(); @@ -160,8 +163,8 @@ static bool __glue_savePatch__(const string &fullPath, const string &name, __glue_fillPatchColumns__(); if (G_Patch.write(fullPath)) { - gu_update_win_label(name.c_str()); - gLog("[glue_savePatch] patch saved as %s\n", fullPath.c_str()); + gu_updateMainWinLabel(name); + gu_log("[glue_savePatch] patch saved as %s\n", fullPath.c_str()); return true; } return false; @@ -175,19 +178,19 @@ void glue_savePatch(void *data) { gdSaveBrowser *browser = (gdSaveBrowser*) data; string name = browser->getName(); - string fullPath = browser->getCurrentPath() + G_SLASH + gStripExt(name) + ".gptc"; + string fullPath = browser->getCurrentPath() + G_SLASH + gu_stripExt(name) + ".gptc"; if (name == "") { gdAlert("Please choose a file name."); return; } - if (gFileExists(fullPath.c_str())) + if (gu_fileExists(fullPath)) if (!gdConfirmWin("Warning", "File exists: overwrite?")) return; if (__glue_savePatch__(fullPath, name, false)) { // false == not a project - G_Conf.patchPath = gDirname(fullPath); + G_Conf.patchPath = gu_dirname(fullPath); browser->do_callback(); } else @@ -202,16 +205,16 @@ void glue_loadPatch(void *data) { gdLoadBrowser *browser = (gdLoadBrowser*) data; string fullPath = browser->getSelectedItem(); - bool isProject = gIsProject(browser->getSelectedItem()); + bool isProject = gu_isProject(browser->getSelectedItem()); browser->showStatusBar(); - gLog("[glue] loading %s...\n", fullPath.c_str()); + gu_log("[glue] loading %s...\n", fullPath.c_str()); string fileToLoad = fullPath; // patch file to read from string basePath = ""; // base path, in case of reading from a project if (isProject) { - fileToLoad = fullPath + G_SLASH + gStripExt(gBasename(fullPath)) + ".gptc"; + fileToLoad = fullPath + G_SLASH + gu_stripExt(gu_basename(fullPath)) + ".gptc"; basePath = fullPath + G_SLASH; } @@ -222,9 +225,9 @@ void glue_loadPatch(void *data) bool deprecated = false; if (res == PATCH_UNREADABLE) { - gLog("[glue] failed reading JSON-based patch. Trying with the deprecated method\n"); + gu_log("[glue] failed reading JSON-based patch. Trying with the deprecated method\n"); deprecated = true; - res = glue_loadPatch__DEPR__(gBasename(fileToLoad).c_str(), fileToLoad.c_str(), + res = glue_loadPatch__DEPR__(gu_basename(fileToLoad).c_str(), fileToLoad.c_str(), browser->getStatusBar(), isProject); } @@ -263,7 +266,7 @@ void glue_loadPatch(void *data) float steps = 0.8 / G_Patch.channels.size(); for (unsigned i=0; ikeyboard->addColumn(col->width); + G_MainWin->keyboard->addColumn(col->width); for (unsigned k=0; kindex) { Channel *ch = glue_addChannel(G_Patch.channels.at(k).column, @@ -283,22 +286,22 @@ void glue_loadPatch(void *data) /* let recorder recompute the actions' positions if the current * samplerate != patch samplerate */ - recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate); + G_Recorder.updateSamplerate(G_Conf.samplerate, G_Patch.samplerate); /* save patchPath by taking the last dir of the broswer, in order to * reuse it the next time */ - G_Conf.patchPath = gDirname(fullPath); + G_Conf.patchPath = gu_dirname(fullPath); /* refresh GUI */ gu_updateControls(); - gu_update_win_label(G_Patch.name.c_str()); + gu_updateMainWinLabel(G_Patch.name); browser->setStatusBar(0.1f); //__glue_setProgressBar__(status, 1.0f); - gLog("[glue] patch loaded successfully\n"); + gu_log("[glue] patch loaded successfully\n"); #ifdef WITH_VST @@ -346,12 +349,12 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat /* mixerHandler will update the samples inside Mixer */ - mh_loadPatch_DEPR_(isProject, gDirname(fpath).c_str()); + mh_loadPatch_DEPR_(isProject, gu_dirname(fpath).c_str()); /* take the patch name and update the main window's title */ G_Patch_DEPR_.getName(); - gu_update_win_label(G_Patch_DEPR_.name); + gu_updateMainWinLabel(G_Patch_DEPR_.name); status->value(0.4f); // progress status: 0.4 //Fl::check(); @@ -372,7 +375,7 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat /* this one is vital: let recorder recompute the actions' positions if * the current samplerate != patch samplerate */ - recorder::updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate); + G_Recorder.updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate); /* update gui */ @@ -385,9 +388,9 @@ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *stat /* save patchPath by taking the last dir of the broswer, in order to * reuse it the next time */ - G_Conf.patchPath = gDirname(fpath).c_str(); + G_Conf.patchPath = gu_dirname(fpath).c_str(); - gLog("[glue] patch %s loaded\n", fname); + gu_log("[glue] patch %s loaded\n", fname); #ifdef WITH_VST if (resPlugins != 1) @@ -408,22 +411,22 @@ void glue_saveProject(void *data) gdSaveBrowser *browser = (gdSaveBrowser*) data; string name = browser->getName(); string folderPath = browser->getCurrentPath(); //browser->getSelectedItem(); - string fullPath = folderPath + G_SLASH + gStripExt(name) + ".gprj"; + string fullPath = folderPath + G_SLASH + gu_stripExt(name) + ".gprj"; if (name == "") { gdAlert("Please choose a project name."); return; } - if (gIsProject(fullPath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?")) + if (gu_isProject(fullPath) && !gdConfirmWin("Warning", "Project exists: overwrite?")) return; - if (!gDirExists(fullPath.c_str()) && !gMkdir(fullPath.c_str())) { - gLog("[glue_saveProject] unable to make project directory!\n"); + if (!gu_dirExists(fullPath) && !gu_mkdir(fullPath)) { + gu_log("[glue_saveProject] unable to make project directory!\n"); return; } - gLog("[glue_saveProject] project dir created: %s\n", fullPath.c_str()); + gu_log("[glue_saveProject] project dir created: %s\n", fullPath.c_str()); /* copy all samples inside the folder. Takes and logical ones are saved * via glue_saveSample() */ @@ -443,13 +446,13 @@ void glue_saveProject(void *data) string samplePath = fullPath + G_SLASH + ch->wave->basename(true); - if (gFileExists(samplePath.c_str())) + if (gu_fileExists(samplePath)) remove(samplePath.c_str()); if (ch->save(samplePath.c_str())) ch->wave->pathfile = samplePath; } - string gptcPath = fullPath + G_SLASH + gStripExt(name.c_str()) + ".gptc"; + string gptcPath = fullPath + G_SLASH + gu_stripExt(name) + ".gptc"; if (__glue_savePatch__(gptcPath, name, true)) // true == it's a project browser->do_callback(); else @@ -471,12 +474,12 @@ void glue_loadSample(void *data) int res = glue_loadChannel((SampleChannel*) browser->getChannel(), fullPath.c_str()); if (res == SAMPLE_LOADED_OK) { - G_Conf.samplePath = gDirname(fullPath); + G_Conf.samplePath = gu_dirname(fullPath); browser->do_callback(); - mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open } else - mainWin->keyboard->printChannelMessage(res); + G_MainWin->keyboard->printChannelMessage(res); } @@ -496,14 +499,14 @@ void glue_saveSample(void *data) /* bruteforce check extension. */ - string filePath = folderPath + G_SLASH + gStripExt(name) + ".wav"; + string filePath = folderPath + G_SLASH + gu_stripExt(name) + ".wav"; - if (gFileExists(filePath)) + if (gu_fileExists(filePath)) if (!gdConfirmWin("Warning", "File exists: overwrite?")) return; if (((SampleChannel*)browser->getChannel())->save(filePath.c_str())) { - G_Conf.samplePath = gDirname(folderPath); + G_Conf.samplePath = gu_dirname(folderPath); browser->do_callback(); } else diff --git a/src/glue/storage.h b/src/glue/storage.h index 98be8e8..a95ec0a 100644 --- a/src/glue/storage.h +++ b/src/glue/storage.h @@ -32,14 +32,6 @@ #define GLUE_STORAGE_H -#include -#include "../core/patch.h" - - -using std::string; -using std::vector; - - void glue_loadPatch (void *data); int glue_loadPatch__DEPR__(const char *fname, const char *fpath, class gProgress *status, bool isProject); void glue_savePatch (void *data); @@ -47,4 +39,5 @@ void glue_saveProject(void *data); void glue_saveSample (void *data); void glue_loadSample (void *data); + #endif diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp index 3e0e614..5c42d26 100644 --- a/src/gui/dialogs/gd_about.cpp +++ b/src/gui/dialogs/gd_about.cpp @@ -33,12 +33,15 @@ #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../core/graphics.h" -#include "../../utils/gui_utils.h" +#include "../../deps/juce/config.h" +#include "../../utils/gui.h" #include "../elems/ge_mixed.h" #include "gd_about.h" -extern Conf G_Conf; +extern Conf G_Conf; +extern KernelAudio G_KernelAudio; +extern KernelMidi G_KernelMidi; gdAbout::gdAbout() @@ -85,8 +88,8 @@ gdAbout::gdAbout() "News, infos, contacts and documentation:\n" "www.giadamusic.com", FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, - kernelAudio::getRtAudioVersion().c_str(), - kernelMidi::getRtMidiVersion().c_str(), + G_KernelAudio.getRtAudioVersion().c_str(), + G_KernelMidi.getRtMidiVersion().c_str(), JANSSON_VERSION #ifdef WITH_VST , JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER); diff --git a/src/gui/dialogs/gd_about.h b/src/gui/dialogs/gd_about.h index 2416740..2b8b6d3 100644 --- a/src/gui/dialogs/gd_about.h +++ b/src/gui/dialogs/gd_about.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_about * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,19 +24,20 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef GD_ABOUT_H #define GD_ABOUT_H -#include -#include + #include "../elems/ge_window.h" -class gdAbout : public gWindow { +class gdAbout : public gWindow +{ private: + class gBox *logo; class gBox *text; class gClick *close; @@ -47,12 +48,12 @@ private: #endif public: + gdAbout(); ~gdAbout(); static void cb_close(Fl_Widget *w, void *p); inline void __cb_close(); - }; #endif diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp index ddfcdaf..9d70506 100644 --- a/src/gui/dialogs/gd_actionEditor.cpp +++ b/src/gui/dialogs/gd_actionEditor.cpp @@ -28,17 +28,17 @@ #include -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/graphics.h" #include "../../core/mixer.h" #include "../../core/recorder.h" #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../elems/ge_actionChannel.h" -#include "../elems/ge_muteChannel.h" -#include "../elems/ge_envelopeChannel.h" -#include "../elems/ge_pianoRoll.h" +#include "../elems/actionEditor.h" +#include "../elems/envelopeEditor.h" +#include "../elems/muteEditor.h" +#include "../elems/noteEditor.h" #include "../elems/ge_mixed.h" #include "gd_actionEditor.h" @@ -100,9 +100,9 @@ gdActionEditor::gdActionEditor(Channel *chan) SampleChannel *ch = (SampleChannel*) chan; - ac = new gActionChannel (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch); - mc = new gMuteChannel (scroller->x(), ac->y()+ac->h()+8, this); - vc = new gEnvelopeChannel (scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume"); + ac = new geActionEditor (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch); + mc = new geMuteEditor (scroller->x(), ac->y()+ac->h()+8, this); + vc = new geEnvelopeEditor(scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume"); scroller->add(ac); //scroller->add(new gResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8)); scroller->add(mc); @@ -121,7 +121,7 @@ gdActionEditor::gdActionEditor(Channel *chan) ac->deactivate(); } else { - pr = new gPianoRollContainer(scroller->x(), upperArea->y()+upperArea->h()+8, this); + pr = new geNoteEditor(scroller->x(), upperArea->y()+upperArea->h()+8, this); scroller->add(pr); scroller->add(new gResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8)); } diff --git a/src/gui/dialogs/gd_actionEditor.h b/src/gui/dialogs/gd_actionEditor.h index 1f7eb40..435619d 100644 --- a/src/gui/dialogs/gd_actionEditor.h +++ b/src/gui/dialogs/gd_actionEditor.h @@ -45,8 +45,8 @@ using std::vector; * This class calculates chan, zoom, frames per beat, and so on. Each * sub-widget contains a pointer to this window to query those data. */ -class gdActionEditor : public gWindow { - +class gdActionEditor : public gWindow +{ private: /* update @@ -74,10 +74,10 @@ public: class gClick *zoomOut; class gScroll *scroller; // widget container - class gActionChannel *ac; - class gMuteChannel *mc; - class gEnvelopeChannel *vc; - class gPianoRollContainer *pr; + class geActionEditor *ac; + class geMuteEditor *mc; + class geEnvelopeEditor *vc; + class geNoteEditor *pr; vector widgets; diff --git a/src/gui/dialogs/gd_beatsInput.cpp b/src/gui/dialogs/gd_beatsInput.cpp index 36599eb..e77e839 100644 --- a/src/gui/dialogs/gd_beatsInput.cpp +++ b/src/gui/dialogs/gd_beatsInput.cpp @@ -27,10 +27,11 @@ * ------------------------------------------------------------------ */ -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/mixer.h" #include "../../core/conf.h" -#include "../../glue/glue.h" +#include "../../core/const.h" +#include "../../glue/main.h" #include "gd_beatsInput.h" #include "gd_mainWindow.h" diff --git a/src/gui/dialogs/gd_bpmInput.cpp b/src/gui/dialogs/gd_bpmInput.cpp index d0186bf..4ad1da2 100644 --- a/src/gui/dialogs/gd_bpmInput.cpp +++ b/src/gui/dialogs/gd_bpmInput.cpp @@ -28,9 +28,10 @@ #include "../../core/conf.h" +#include "../../core/const.h" #include "../../core/mixer.h" -#include "../../glue/glue.h" -#include "../../utils/gui_utils.h" +#include "../../glue/main.h" +#include "../../utils/gui.h" #include "../elems/ge_mixed.h" #include "gd_bpmInput.h" #include "gd_mainWindow.h" diff --git a/src/gui/dialogs/gd_browser.cpp b/src/gui/dialogs/gd_browser.cpp index 448ad74..0c45a18 100644 --- a/src/gui/dialogs/gd_browser.cpp +++ b/src/gui/dialogs/gd_browser.cpp @@ -32,12 +32,13 @@ #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/conf.h" -#include "../../glue/glue.h" +#include "../../core/const.h" +#include "../../glue/main.h" #include "../../glue/channel.h" #include "../../glue/storage.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../elems/ge_browser.h" -#include "../elems/ge_channel.h" +#include "../elems/channel.h" #include "gd_browser.h" @@ -102,7 +103,7 @@ gdBaseBrowser::~gdBaseBrowser() G_Conf.browserW = w(); G_Conf.browserH = h(); G_Conf.browserPosition = browser->position(); - G_Conf.browserLastPath = gDirname(browser->getSelectedItem()); + G_Conf.browserLastPath = gu_dirname(browser->getSelectedItem()); G_Conf.browserLastValue = browser->value(); } @@ -197,7 +198,7 @@ void gdSaveBrowser::__cb_down() /* if the selected item is a directory just load its content. If it's a file * use it as the file name (i.e. fill name->value()). */ - if (gIsDir(path)) { + if (gu_isDir(path)) { browser->loadDir(path); where->value(browser->getCurrentDir().c_str()); } @@ -261,7 +262,7 @@ void gdLoadBrowser::__cb_down() { string path = browser->getSelectedItem(); - if (path.empty() || !gIsDir(path)) // when click on an empty area or not a dir + if (path.empty() || !gu_isDir(path)) // when click on an empty area or not a dir return; browser->loadDir(path); diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp index 5d7da03..832b75a 100644 --- a/src/gui/dialogs/gd_config.cpp +++ b/src/gui/dialogs/gd_config.cpp @@ -27,14 +27,17 @@ * -------------------------------------------------------------------------- */ +#include +#include #include "../../core/conf.h" #include "../../core/midiMapConf.h" #include "../../core/patch_DEPR_.h" #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../core/pluginHost.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../utils/log.h" +#include "../../utils/string.h" #include "../elems/ge_mixed.h" #include "gd_config.h" #include "gd_keyGrabber.h" @@ -44,6 +47,8 @@ extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; +extern KernelAudio G_KernelAudio; +extern KernelMidi G_KernelMidi; extern bool G_audio_status; extern MidiMapConf G_MidiMap; @@ -131,11 +136,11 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) #if defined(__linux__) - if (kernelAudio::hasAPI(RtAudio::LINUX_ALSA)) + if (G_KernelAudio.hasAPI(RtAudio::LINUX_ALSA)) soundsys->add("ALSA"); - if (kernelAudio::hasAPI(RtAudio::UNIX_JACK)) + if (G_KernelAudio.hasAPI(RtAudio::UNIX_JACK)) soundsys->add("Jack"); - if (kernelAudio::hasAPI(RtAudio::LINUX_PULSE)) + if (G_KernelAudio.hasAPI(RtAudio::LINUX_PULSE)) soundsys->add("PulseAudio"); switch (G_Conf.soundSystem) { @@ -157,11 +162,11 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) #elif defined(_WIN32) - if (kernelAudio::hasAPI(RtAudio::WINDOWS_DS)) + if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_DS)) soundsys->add("DirectSound"); - if (kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO)) + if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_ASIO)) soundsys->add("ASIO"); - if (kernelAudio::hasAPI(RtAudio::WINDOWS_WASAPI)) + if (G_KernelAudio.hasAPI(RtAudio::WINDOWS_WASAPI)) soundsys->add("WASAPI"); switch (G_Conf.soundSystem) { @@ -181,7 +186,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) #elif defined (__APPLE__) - if (kernelAudio::hasAPI(RtAudio::MACOSX_CORE)) + if (G_KernelAudio.hasAPI(RtAudio::MACOSX_CORE)) soundsys->add("CoreAudio"); switch (G_Conf.soundSystem) { @@ -213,10 +218,10 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) /* fill frequency dropdown menu */ /* TODO - add fetchFrequencies() */ - int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value()); + int nfreq = G_KernelAudio.getTotalFreqs(sounddevOut->value()); for (int i=0; ivalue(), i); - samplerate->add(gItoa(freq).c_str()); + int freq = G_KernelAudio.getFreq(sounddevOut->value(), i); + samplerate->add(gu_itoa(freq).c_str()); if (freq == G_Conf.samplerate) samplerate->value(i); } @@ -241,7 +246,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) buffersize->add("1024"); buffersize->add("2048"); buffersize->add("4096"); - buffersize->showItem(gItoa(G_Conf.buffersize).c_str()); + buffersize->showItem(gu_itoa(G_Conf.buffersize).c_str()); rsmpQuality->add("Sinc best quality (very slow)"); rsmpQuality->add("Sinc medium quality (slow)"); @@ -250,7 +255,7 @@ gTabAudio::gTabAudio(int X, int Y, int W, int H) rsmpQuality->add("Linear (very fast)"); rsmpQuality->value(G_Conf.rsmpQuality); - delayComp->value(gItoa(G_Conf.delayComp).c_str()); + delayComp->value(gu_itoa(G_Conf.delayComp).c_str()); delayComp->type(FL_INT_INPUT); delayComp->maximum_size(5); @@ -293,7 +298,7 @@ void gTabAudio::__cb_fetchOutChans() void gTabAudio::__cb_showInputInfo() { - unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); + unsigned dev = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value())); new gdDevInfo(dev); } @@ -303,7 +308,7 @@ void gTabAudio::__cb_showInputInfo() void gTabAudio::__cb_showOutputInfo() { - unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); + unsigned dev = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value())); new gdDevInfo(dev); } @@ -374,8 +379,8 @@ void gTabAudio::fetchInChans(int menuItem) channelsIn->clear(); - unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); - unsigned chs = kernelAudio::getMaxInChans(dev); + unsigned dev = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value())); + unsigned chs = G_KernelAudio.getMaxInChans(dev); if (chs == 0) { channelsIn->add("none"); @@ -398,8 +403,8 @@ void gTabAudio::fetchOutChans(int menuItem) { channelsOut->clear(); - unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); - unsigned chs = kernelAudio::getMaxOutChans(dev); + unsigned dev = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value())); + unsigned chs = G_KernelAudio.getMaxOutChans(dev); if (chs == 0) { channelsOut->add("none"); @@ -427,11 +432,11 @@ int gTabAudio::findMenuDevice(gChoice *m, int device) return 0; for (int i=0; isize(); i++) { - if (kernelAudio::getDeviceName(device) == "") + if (G_KernelAudio.getDeviceName(device) == "") continue; if (m->text(i) == NULL) continue; - if (m->text(i) == kernelAudio::getDeviceName(device)) + if (m->text(i) == G_KernelAudio.getDeviceName(device)) return i; } @@ -444,7 +449,7 @@ int gTabAudio::findMenuDevice(gChoice *m, int device) void gTabAudio::fetchSoundDevs() { - if (kernelAudio::numDevs == 0) { + if (G_KernelAudio.numDevs == 0) { sounddevOut->add("-- no devices found --"); sounddevOut->value(0); sounddevIn->add("-- no devices found --"); @@ -462,11 +467,11 @@ void gTabAudio::fetchSoundDevs() sounddevIn->add("(disabled)"); - for (unsigned i=0; i 0) + if (G_KernelAudio.getMaxOutChans(i) > 0) sounddevOut->add(tmp.c_str()); - if (kernelAudio::getMaxInChans(i) > 0) + if (G_KernelAudio.getMaxInChans(i) > 0) sounddevIn->add(tmp.c_str()); } @@ -534,6 +539,8 @@ void gTabAudio::save() G_Conf.soundSystem = SYS_API_DS; else if (text == "ASIO") G_Conf.soundSystem = SYS_API_ASIO; + else if (text == "WASAPI") + G_Conf.soundSystem = SYS_API_WASAPI; #elif defined (__APPLE__) @@ -544,8 +551,8 @@ void gTabAudio::save() /* use the device name to search into the drop down menu's */ - G_Conf.soundDeviceOut = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); - G_Conf.soundDeviceIn = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); + G_Conf.soundDeviceOut = G_KernelAudio.getDeviceByName(sounddevOut->text(sounddevOut->value())); + G_Conf.soundDeviceIn = G_KernelAudio.getDeviceByName(sounddevIn->text(sounddevIn->value())); G_Conf.channelsOut = channelsOut->value(); G_Conf.channelsIn = channelsIn->value(); G_Conf.limitOutput = limitOutput->value(); @@ -620,7 +627,7 @@ gTabMidi::gTabMidi(int X, int Y, int W, int H) void gTabMidi::fetchOutPorts() { - if (kernelMidi::numOutPorts == 0) { + if (G_KernelMidi.numOutPorts == 0) { portOut->add("-- no ports found --"); portOut->value(0); portOut->deactivate(); @@ -629,8 +636,8 @@ void gTabMidi::fetchOutPorts() { portOut->add("(disabled)"); - for (unsigned i=0; iadd(gu_removeFltkChars(kernelMidi::getOutPortName(i)).c_str()); + for (unsigned i=0; iadd(gu_removeFltkChars(G_KernelMidi.getOutPortName(i)).c_str()); portOut->value(G_Conf.midiPortOut+1); // +1 because midiPortOut=-1 is '(disabled)' } @@ -641,7 +648,7 @@ void gTabMidi::fetchOutPorts() { void gTabMidi::fetchInPorts() { - if (kernelMidi::numInPorts == 0) { + if (G_KernelMidi.numInPorts == 0) { portIn->add("-- no ports found --"); portIn->value(0); portIn->deactivate(); @@ -650,8 +657,8 @@ void gTabMidi::fetchInPorts() portIn->add("(disabled)"); - for (unsigned i=0; iadd(gu_removeFltkChars(kernelMidi::getInPortName(i)).c_str()); + for (unsigned i=0; iadd(gu_removeFltkChars(G_KernelMidi.getInPortName(i)).c_str()); portIn->value(G_Conf.midiPortIn+1); // +1 because midiPortIn=-1 is '(disabled)' } @@ -678,7 +685,7 @@ void gTabMidi::fetchMidiMaps() } /* Preselect the 0 midimap if nothing is selected but midimaps exist. */ - + if (midiMap->value() == -1 && G_MidiMap.maps.size() > 0) midiMap->value(0); } @@ -722,14 +729,14 @@ void gTabMidi::fetchSystems() { #if defined(__linux__) - if (kernelMidi::hasAPI(RtMidi::LINUX_ALSA)) + if (G_KernelMidi.hasAPI(RtMidi::LINUX_ALSA)) system->add("ALSA"); - if (kernelMidi::hasAPI(RtMidi::UNIX_JACK)) + if (G_KernelMidi.hasAPI(RtMidi::UNIX_JACK)) system->add("Jack"); #elif defined(_WIN32) - if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM)) + if (G_KernelMidi.hasAPI(RtMidi::WINDOWS_MM)) system->add("Multimedia MIDI"); #elif defined (__APPLE__) @@ -887,7 +894,7 @@ gTabPlugins::gTabPlugins(int X, int Y, int W, int H) void gTabPlugins::updateCount() { - string scanLabel = "Scan (" + gItoa(G_PluginHost.countAvailablePlugins()) + " found)"; + string scanLabel = "Scan (" + gu_itoa(G_PluginHost.countAvailablePlugins()) + " found)"; scanButton->label(scanLabel.c_str()); } @@ -903,7 +910,7 @@ void gTabPlugins::cb_scan(Fl_Widget *w, void *p) { ((gTabPlugins*)p)->__cb_scan( void gTabPlugins::cb_onScan(float progress, void *p) { - string l = "Scan in progress (" + gItoa((int)(progress*100)) + "%). Please wait..."; + string l = "Scan in progress (" + gu_itoa((int)(progress*100)) + "%). Please wait..."; ((gTabPlugins *)p)->info->label(l.c_str()); Fl::wait(); } @@ -916,7 +923,7 @@ void gTabPlugins::__cb_scan(Fl_Widget *w) { info->show(); G_PluginHost.scanDir(folderPath->value(), cb_onScan, (void*) this); - G_PluginHost.saveList(gGetHomePath() + G_SLASH + "plugins.xml"); + G_PluginHost.saveList(gu_getHomePath() + G_SLASH + "plugins.xml"); info->hide(); updateCount(); } diff --git a/src/gui/dialogs/gd_config.h b/src/gui/dialogs/gd_config.h index d2e7580..fc7b64a 100644 --- a/src/gui/dialogs/gd_config.h +++ b/src/gui/dialogs/gd_config.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_config * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,18 +24,14 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + #ifndef GD_CONFIG_H #define GD_CONFIG_H -#include -#include -#include -#include "../elems/ge_window.h" - -using std::string; +#include "../elems/ge_window.h" class gdConfig : public gWindow diff --git a/src/gui/dialogs/gd_devInfo.cpp b/src/gui/dialogs/gd_devInfo.cpp index 5055928..3f901a3 100644 --- a/src/gui/dialogs/gd_devInfo.cpp +++ b/src/gui/dialogs/gd_devInfo.cpp @@ -28,17 +28,21 @@ #include "../../core/kernelAudio.h" -#include "../../utils/gui_utils.h" -#include "../../utils/utils.h" +#include "../../utils/gui.h" +#include "../../utils/string.h" #include "../elems/ge_mixed.h" #include "gd_devInfo.h" +extern KernelAudio G_KernelAudio; + + using std::string; gdDevInfo::gdDevInfo(unsigned dev) -: Fl_Window(340, 300, "Device information") { + : Fl_Window(340, 300, "Device information") +{ set_modal(); text = new gBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); @@ -48,22 +52,22 @@ gdDevInfo::gdDevInfo(unsigned dev) string body = ""; int lines = 7; - body = "Device name: " + kernelAudio::getDeviceName(dev) + "\n"; - body += "Total output(s): " + gItoa(kernelAudio::getMaxOutChans(dev)) + "\n"; - body += "Total intput(s): " + gItoa(kernelAudio::getMaxInChans(dev)) + "\n"; - body += "Duplex channel(s): " + gItoa(kernelAudio::getDuplexChans(dev)) + "\n"; - body += "Default output: " + string(kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n"; - body += "Default input: " + string(kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n"; + body = "Device name: " + G_KernelAudio.getDeviceName(dev) + "\n"; + body += "Total output(s): " + gu_itoa(G_KernelAudio.getMaxOutChans(dev)) + "\n"; + body += "Total intput(s): " + gu_itoa(G_KernelAudio.getMaxInChans(dev)) + "\n"; + body += "Duplex channel(s): " + gu_itoa(G_KernelAudio.getDuplexChans(dev)) + "\n"; + body += "Default output: " + string(G_KernelAudio.isDefaultOut(dev) ? "yes" : "no") + "\n"; + body += "Default input: " + string(G_KernelAudio.isDefaultIn(dev) ? "yes" : "no") + "\n"; - int totalFreq = kernelAudio::getTotalFreqs(dev); - body += "Supported frequencies: " + gItoa(totalFreq); + int totalFreq = G_KernelAudio.getTotalFreqs(dev); + body += "Supported frequencies: " + gu_itoa(totalFreq); for (int i=0; icopy_label(body.c_str()); diff --git a/src/gui/dialogs/gd_editor.cpp b/src/gui/dialogs/gd_editor.cpp index 501edfe..af5d55b 100644 --- a/src/gui/dialogs/gd_editor.cpp +++ b/src/gui/dialogs/gd_editor.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_editor * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,32 +24,27 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ -#include "../../utils/gui_utils.h" -#include "../../glue/glue.h" +#include "../../glue/channel.h" #include "../../core/waveFx.h" #include "../../core/conf.h" +#include "../../core/const.h" #include "../../core/graphics.h" -#include "../../core/mixerHandler.h" -#include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/mixer.h" #include "../../core/wave.h" +#include "../elems/channel.h" #include "../elems/ge_waveform.h" #include "../elems/ge_mixed.h" -#include "../elems/ge_channel.h" #include "../elems/ge_waveTools.h" -#include "../elems/ge_keyboard.h" -#include "gd_editor.h" -#include "gd_mainWindow.h" #include "gd_warnings.h" +#include "gd_editor.h" -extern Mixer G_Mixer; -extern gdMainWindow *mainWin; -extern Conf G_Conf; +extern Mixer G_Mixer; +extern Conf G_Conf; gdEditor::gdEditor(SampleChannel *ch) @@ -81,28 +76,28 @@ gdEditor::gdEditor(SampleChannel *ch) Fl_Group *tools = new Fl_Group(8, waveTools->y()+waveTools->h()+8, w()-16, 130); tools->begin(); - volume = new gDial (tools->x()+42, tools->y(), 20, 20, "Volume"); + volume = new gDial (tools->x()+50, tools->y(), 20, 20, "Volume"); volumeNum = new gInput(volume->x()+volume->w()+4, tools->y(), 46, 20, "dB"); - boost = new gDial (volumeNum->x()+volumeNum->w()+80, tools->y(), 20, 20, "Boost"); - boostNum = new gInput(boost->x()+boost->w()+4, tools->y(), 46, 20, "dB"); + boost = new gDial (volumeNum->x()+volumeNum->w()+108, tools->y(), 20, 20, "Boost"); + boostNum = new gInput(boost->x()+boost->w()+4, tools->y(), 44, 20, "dB"); normalize = new gClick(boostNum->x()+boostNum->w()+54, tools->y(), 70, 20, "Normalize"); pan = new gDial (normalize->x()+normalize->w()+40, tools->y(), 20, 20, "Pan"); panNum = new gInput(pan->x()+pan->w()+4, tools->y(), 45, 20, "%"); - pitch = new gDial (tools->x()+42, volume->y()+volume->h()+4, 20, 20, "Pitch"); + pitch = new gDial (tools->x()+50, volume->y()+volume->h()+4, 20, 20, "Pitch"); pitchNum = new gInput(pitch->x()+pitch->w()+4, volume->y()+volume->h()+4, 46, 20); - pitchToBar = new gClick(pitchNum->x()+pitchNum->w()+4, volume->y()+volume->h()+4, 46, 20, "To bar"); - pitchToSong = new gClick(pitchToBar->x()+pitchToBar->w()+4, volume->y()+volume->h()+4, 46, 20, "To song"); - pitchHalf = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 21, 20, "÷"); - pitchDouble = new gClick(pitchHalf->x()+pitchHalf->w()+4, volume->y()+volume->h()+4, 21, 20, "×"); + pitchToBar = new gClick(pitchNum->x()+pitchNum->w()+4, volume->y()+volume->h()+4, 60, 20, "To bar"); + pitchToSong = new gClick(pitchToBar->x()+pitchToBar->w()+4, volume->y()+volume->h()+4, 60, 20, "To song"); + pitchHalf = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 20, 20, "", divideOff_xpm, divideOn_xpm); + pitchDouble = new gClick(pitchHalf->x()+pitchHalf->w()+4, volume->y()+volume->h()+4, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm); pitchReset = new gClick(pitchDouble->x()+pitchDouble->w()+4, volume->y()+volume->h()+4, 46, 20, "Reset"); reload = new gClick(pitchReset->x()+pitchReset->w()+4, volume->y()+volume->h()+4, 70, 20, "Reload"); - chanStart = new gInput(tools->x()+52, pitch->y()+pitch->h()+4, 60, 20, "Start"); - chanEnd = new gInput(chanStart->x()+chanStart->w()+40, pitch->y()+pitch->h()+4, 60, 20, "End"); - resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4, pitch->y()+pitch->h()+4, 46, 20, "Reset"); + chanStart = new gInput(tools->x()+60, pitch->y()+pitch->h()+4, 60, 20, "Range"); + chanEnd = new gInput(chanStart->x()+chanStart->w()+4, pitch->y()+pitch->h()+4, 60, 20, ""); + resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4, pitch->y()+pitch->h()+4, 60, 20, "Reset"); tools->end(); tools->resizable(new gBox(panNum->x()+panNum->w()+4, tools->y(), 80, tools->h())); @@ -202,7 +197,7 @@ gdEditor::gdEditor(SampleChannel *ch) if (ch->panRight < 1.0f) { char buf[8]; - sprintf(buf, "%d L", (int) abs((ch->panRight * 100.0f) - 100)); + sprintf(buf, "%d L", (int) std::abs((ch->panRight * 100.0f) - 100)); pan->value(ch->panRight); panNum->value(buf); } @@ -212,7 +207,7 @@ gdEditor::gdEditor(SampleChannel *ch) } else { char buf[8]; - sprintf(buf, "%d R", (int) abs((ch->panLeft * 100.0f) - 100)); + sprintf(buf, "%d R", (int) std::abs((ch->panLeft * 100.0f) - 100)); pan->value(2.0f - ch->panLeft); panNum->value(buf); } @@ -231,7 +226,7 @@ gdEditor::gdEditor(SampleChannel *ch) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ gdEditor::~gdEditor() @@ -245,7 +240,7 @@ gdEditor::~gdEditor() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::cb_setChanPos (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setChanPos(); } @@ -270,7 +265,7 @@ void gdEditor::cb_changeGrid (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb void gdEditor::cb_enableSnap (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_enableSnap(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_enableSnap() @@ -279,7 +274,7 @@ void gdEditor::__cb_enableSnap() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitchToBar() @@ -288,7 +283,7 @@ void gdEditor::__cb_setPitchToBar() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitchToSong() @@ -297,7 +292,7 @@ void gdEditor::__cb_setPitchToSong() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_resetPitch() @@ -306,7 +301,7 @@ void gdEditor::__cb_resetPitch() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setChanPos() @@ -321,7 +316,7 @@ void gdEditor::__cb_setChanPos() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_resetStartEnd() @@ -330,7 +325,7 @@ void gdEditor::__cb_resetStartEnd() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setVolume() @@ -339,7 +334,7 @@ void gdEditor::__cb_setVolume() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setVolumeNum() @@ -348,7 +343,7 @@ void gdEditor::__cb_setVolumeNum() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setBoost() @@ -362,7 +357,7 @@ void gdEditor::__cb_setBoost() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setBoostNum() @@ -372,7 +367,7 @@ void gdEditor::__cb_setBoostNum() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_normalize() @@ -390,7 +385,7 @@ void gdEditor::__cb_normalize() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_panning() @@ -399,7 +394,7 @@ void gdEditor::__cb_panning() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_reload() @@ -426,7 +421,7 @@ void gdEditor::__cb_reload() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitch() @@ -435,7 +430,7 @@ void gdEditor::__cb_setPitch() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitchNum() @@ -444,7 +439,7 @@ void gdEditor::__cb_setPitchNum() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitchHalf() @@ -453,7 +448,7 @@ void gdEditor::__cb_setPitchHalf() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_setPitchDouble() @@ -462,7 +457,7 @@ void gdEditor::__cb_setPitchDouble() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_zoomIn() @@ -472,7 +467,7 @@ void gdEditor::__cb_zoomIn() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_zoomOut() @@ -482,7 +477,7 @@ void gdEditor::__cb_zoomOut() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdEditor::__cb_changeGrid() diff --git a/src/gui/dialogs/gd_editor.h b/src/gui/dialogs/gd_editor.h index cd7b9ae..c9ffe74 100644 --- a/src/gui/dialogs/gd_editor.h +++ b/src/gui/dialogs/gd_editor.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_editor * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,19 +24,18 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + #ifndef GD_EDITOR_H #define GD_EDITOR_H -#include -#include -#include -#include "../elems/ge_window.h" +#include "../elems/ge_window.h" -class gdEditor : public gWindow { +class gdEditor : public gWindow +{ private: static void cb_setChanPos (Fl_Widget *w, void *p); @@ -113,4 +112,5 @@ public: class SampleChannel *ch; }; + #endif diff --git a/src/gui/dialogs/gd_keyGrabber.cpp b/src/gui/dialogs/gd_keyGrabber.cpp index 47a8a54..508867b 100644 --- a/src/gui/dialogs/gd_keyGrabber.cpp +++ b/src/gui/dialogs/gd_keyGrabber.cpp @@ -27,7 +27,7 @@ * -------------------------------------------------------------------------- */ -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" @@ -35,8 +35,8 @@ #include "../../utils/log.h" #include "../elems/ge_keyboard.h" #include "../elems/ge_mixed.h" -#include "../elems/ge_channel.h" -#include "../elems/ge_channelButton.h" +#include "../elems/channel.h" +#include "../elems/channelButton.h" #include "gd_keyGrabber.h" #include "gd_config.h" #include "gd_mainWindow.h" @@ -132,13 +132,13 @@ int gdKeyGrabber::handle(int e) && x != FL_End && x != ' ') { - gLog("set key '%c' (%d) for channel %d\n", x, x, ch->index); + gu_log("set key '%c' (%d) for channel %d\n", x, x, ch->index); setButtonLabel(x); updateText(x); break; } else - gLog("invalid key\n"); + gu_log("invalid key\n"); } } return(ret); diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp index b2012c2..dba5764 100644 --- a/src/gui/dialogs/gd_mainWindow.cpp +++ b/src/gui/dialogs/gd_mainWindow.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_mainWindow * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifdef __linux__ @@ -40,9 +40,10 @@ #include "../../core/sampleChannel.h" #include "../../core/init.h" #include "../../core/patch_DEPR_.h" +#include "../../core/patch.h" #include "../../core/conf.h" #include "../../core/pluginHost.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" #include "../../glue/storage.h" #include "../elems/ge_keyboard.h" #include "gd_warnings.h" @@ -60,7 +61,7 @@ extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Conf G_Conf; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; extern bool G_quit; extern bool G_audio_status; @@ -76,7 +77,7 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg size_range(GUI_WIDTH, GUI_HEIGHT); menu = new gMenu(8, -1); - inOut = new gInOut(414, 8); + inOut = new gInOut(412, 8); controller = new gController(8, 39); timing = new gTiming(628, 44); beatMeter = new gBeatMeter(100, 83, 609, 20); @@ -117,13 +118,13 @@ gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **arg } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { mainWin->__cb_endprogram(); } +void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { G_MainWin->__cb_endprogram(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gdMainWindow::__cb_endprogram() @@ -136,28 +137,28 @@ void gdMainWindow::__cb_endprogram() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gInOut::gInOut(int x, int y) - : Fl_Group(x, y, 394, 20) + : Fl_Group(x, y, 396, 20) { begin(); #if defined(WITH_VST) masterFxIn = new gFxButton (x, y, 20, 20, fxOff_xpm, fxOn_xpm); inVol = new gDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20); - inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10); - inToOut = new gClick (inMeter->x()+inMeter->w()+4, y+5, 10, 10, ""); - outMeter = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+5, 140, 10); + inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+4, 140, 12); + inToOut = new gClick (inMeter->x()+inMeter->w()+4, y+4, 12, 12, "", inputToOutputOff_xpm, inputToOutputOn_xpm); + outMeter = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+4, 140, 12); outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); masterFxOut = new gFxButton (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm); #else inVol = new gDial (x+62, y, 20, 20); - inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10); - outMeter = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 10); + inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 12); + outMeter = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 12); outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); #endif @@ -179,7 +180,7 @@ gInOut::gInOut(int x, int y) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gInOut::cb_outVol (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_outVol(); } @@ -191,7 +192,7 @@ void gInOut::cb_inToOut (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_inToO #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gInOut::__cb_outVol() @@ -200,7 +201,7 @@ void gInOut::__cb_outVol() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gInOut::__cb_inVol() @@ -209,18 +210,18 @@ void gInOut::__cb_inVol() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ #ifdef WITH_VST void gInOut::__cb_masterFxOut() { - gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST); + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST); } void gInOut::__cb_masterFxIn() { - gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST); + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST); } void gInOut::__cb_inToOut() @@ -230,7 +231,7 @@ void gInOut::__cb_inToOut() #endif -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gInOut::refresh() @@ -242,9 +243,9 @@ void gInOut::refresh() } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gMenu::gMenu(int x, int y) @@ -268,7 +269,7 @@ gMenu::gMenu(int x, int y) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); } @@ -277,25 +278,25 @@ void gMenu::cb_file (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); } void gMenu::cb_edit (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gMenu::__cb_about() { - gu_openSubWindow(mainWin, new gdAbout(), WID_ABOUT); + gu_openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gMenu::__cb_config() { - gu_openSubWindow(mainWin, new gdConfig(380, 370), WID_CONFIG); + gu_openSubWindow(G_MainWin, new gdConfig(380, 370), WID_CONFIG); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gMenu::__cb_file() @@ -322,11 +323,11 @@ void gMenu::__cb_file() if (strcmp(m->label(), "Open patch or project...") == 0) { //gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH); - //gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + //gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); gWindow *childWin = new gdLoadBrowser(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH, "Load patch or project", G_Conf.patchPath, glue_loadPatch, NULL); - gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Save patch...") == 0) { @@ -336,24 +337,24 @@ void gMenu::__cb_file() gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH, "Save patch", G_Conf.patchPath, G_Patch.name, glue_savePatch, NULL); - gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Save project...") == 0) { gWindow *childWin = new gdSaveBrowser(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH, "Save project", G_Conf.patchPath, G_Patch.name, glue_saveProject, NULL); - gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Quit Giada") == 0) { - mainWin->do_callback(); + G_MainWin->do_callback(); return; } } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gMenu::__cb_edit() @@ -396,14 +397,14 @@ void gMenu::__cb_edit() if (strcmp(m->label(), "Clear all samples") == 0) { if (!gdConfirmWin("Warning", "Clear all samples: are you sure?")) return; - mainWin->delSubWindow(WID_SAMPLE_EDITOR); + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); glue_clearAllSamples(); return; } if (strcmp(m->label(), "Clear all actions") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; - mainWin->delSubWindow(WID_ACTION_EDITOR); + G_MainWin->delSubWindow(WID_ACTION_EDITOR); glue_clearAllRecs(); return; } @@ -415,19 +416,19 @@ void gMenu::__cb_edit() return; } if (strcmp(m->label(), "Remove empty columns") == 0) { - mainWin->keyboard->organizeColumns(); + G_MainWin->keyboard->organizeColumns(); return; } if (strcmp(m->label(), "Setup global MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0); + gu_openSubWindow(G_MainWin, new gdMidiInputMaster(), 0); return; } } -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ gTiming::gTiming(int x, int y) @@ -438,8 +439,8 @@ gTiming::gTiming(int x, int y) quantizer = new gChoice(x, y, 40, 20, "", false); bpm = new gClick (quantizer->x()+quantizer->w()+4, y, 40, 20); meter = new gClick (bpm->x()+bpm->w()+8, y, 40, 20, "4/1"); - multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", beatsMultiplyOff_xpm, beatsMultiplyOn_xpm); - divider = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", beatsDivideOff_xpm, beatsDivideOn_xpm); + multiplier = new gClick (meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm); + divider = new gClick (multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm); end(); @@ -464,7 +465,7 @@ gTiming::gTiming(int x, int y) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::cb_bpm (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); } @@ -474,25 +475,25 @@ void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multipl void gTiming::cb_divider (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::__cb_bpm() { - gu_openSubWindow(mainWin, new gdBpmInput(bpm->label()), WID_BPM); + gu_openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::__cb_meter() { - gu_openSubWindow(mainWin, new gdBeatsInput(), WID_BEATS); + gu_openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::__cb_quantizer() @@ -501,7 +502,7 @@ void gTiming::__cb_quantizer() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::__cb_multiplier() @@ -510,7 +511,7 @@ void gTiming::__cb_multiplier() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::__cb_divider() @@ -519,7 +520,7 @@ void gTiming::__cb_divider() } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::setBpm(const char *v) @@ -536,7 +537,7 @@ void gTiming::setBpm(float v) } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ void gTiming::setMeter(int beats, int bars) diff --git a/src/gui/dialogs/gd_mainWindow.h b/src/gui/dialogs/gd_mainWindow.h index 7adc52d..a0a0489 100644 --- a/src/gui/dialogs/gd_mainWindow.h +++ b/src/gui/dialogs/gd_mainWindow.h @@ -1,9 +1,9 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * gd_mainWindow * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -23,7 +23,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef GD_MAINWINDOW_H @@ -37,7 +37,7 @@ #include "../elems/ge_controller.h" -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ class gdMainWindow : public gWindow @@ -60,7 +60,7 @@ public: }; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ class gInOut : public Fl_Group @@ -108,7 +108,7 @@ public: }; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ class gMenu : public Fl_Group @@ -136,7 +136,7 @@ public: }; -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ class gTiming : public Fl_Group diff --git a/src/gui/dialogs/gd_midiInput.cpp b/src/gui/dialogs/gd_midiInput.cpp index ce7f468..e713416 100644 --- a/src/gui/dialogs/gd_midiInput.cpp +++ b/src/gui/dialogs/gd_midiInput.cpp @@ -27,17 +27,23 @@ * -------------------------------------------------------------------------- */ -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/kernelMidi.h" #include "../../core/conf.h" +#include "../../core/const.h" #include "../../core/sampleChannel.h" #include "../../utils/log.h" +#include "../../utils/string.h" #include "../elems/ge_mixed.h" #include "../elems/ge_midiIoTools.h" #include "gd_midiInput.h" -extern Conf G_Conf; +extern Conf G_Conf; +extern KernelMidi G_KernelMidi; + + +using std::string; gdMidiInput::gdMidiInput(int w, int h, const char *title) @@ -49,16 +55,18 @@ gdMidiInput::gdMidiInput(int w, int h, const char *title) /* -------------------------------------------------------------------------- */ -gdMidiInput::~gdMidiInput() { - kernelMidi::stopMidiLearn(); +gdMidiInput::~gdMidiInput() +{ + G_KernelMidi.stopMidiLearn(); } /* -------------------------------------------------------------------------- */ -void gdMidiInput::stopMidiLearn(gLearner *learner) { - kernelMidi::stopMidiLearn(); +void gdMidiInput::stopMidiLearn(gLearner *learner) +{ + G_KernelMidi.stopMidiLearn(); learner->updateValue(); } @@ -66,17 +74,19 @@ void gdMidiInput::stopMidiLearn(gLearner *learner) { /* -------------------------------------------------------------------------- */ -void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { +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); + gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); } /* -------------------------------------------------------------------------- */ -void gdMidiInput::cb_learn(uint32_t msg, void *d) { +void gdMidiInput::cb_learn(uint32_t msg, void *d) +{ cbData *data = (cbData*) d; gdMidiInput *window = (gdMidiInput*) data->window; gLearner *learner = data->learner; @@ -95,7 +105,8 @@ void gdMidiInput::cb_close(Fl_Widget *w, void *p) { ((gdMidiInput*)p)->__cb_clo /* -------------------------------------------------------------------------- */ -void gdMidiInput::__cb_close() { +void gdMidiInput::__cb_close() +{ do_callback(); } @@ -106,12 +117,11 @@ void gdMidiInput::__cb_close() { gdMidiInputChannel::gdMidiInputChannel(Channel *ch) - : gdMidiInput(300, 206, "MIDI Input Setup"), + : gdMidiInput(300, 230, "MIDI Input Setup"), ch(ch) { - char title[64]; - sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1); - label(title); + string title = "MIDI Input Setup (channel " + gu_itoa(ch->index+1) + ")"; + label(title.c_str()); set_modal(); @@ -119,16 +129,17 @@ gdMidiInputChannel::gdMidiInputChannel(Channel *ch) 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; + new gLearner(8, 102, w()-16, "arm", cb_learn, &ch->midiInArm); + new gLearner(8, 126, w()-16, "mute", cb_learn, &ch->midiInMute); + new gLearner(8, 150, w()-16, "solo", cb_learn, &ch->midiInSolo); + new gLearner(8, 174, w()-16, "volume", cb_learn, &ch->midiInVolume); + int yy = 202; 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; + size(300, 278); + new gLearner(8, 198, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); + new gLearner(8, 222, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); + yy = 250; } ok = new gButton(w()-88, yy, 80, 20, "Close"); @@ -151,7 +162,8 @@ void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiInputChanne /* -------------------------------------------------------------------------- */ -void gdMidiInputChannel::__cb_enable() { +void gdMidiInputChannel::__cb_enable() +{ ch->midiIn = enable->value(); } diff --git a/src/gui/dialogs/gd_midiInput.h b/src/gui/dialogs/gd_midiInput.h index 0ade193..eb236e7 100644 --- a/src/gui/dialogs/gd_midiInput.h +++ b/src/gui/dialogs/gd_midiInput.h @@ -31,17 +31,14 @@ #define GD_MIDI_INPUT_H -#include "../../core/kernelMidi.h" -#include "../../utils/utils.h" #include "../elems/ge_window.h" -#include "../elems/ge_mixed.h" class gdMidiInput : public gWindow { protected: - gClick *ok; + class gClick *ok; void stopMidiLearn(class gLearner *l); @@ -70,8 +67,7 @@ private: class Channel *ch; - gCheck *enable; - + class gCheck *enable; //gVector items; for future use, with vst parameters diff --git a/src/gui/dialogs/gd_midiOutput.cpp b/src/gui/dialogs/gd_midiOutput.cpp index 69aea2c..5b2be1f 100644 --- a/src/gui/dialogs/gd_midiOutput.cpp +++ b/src/gui/dialogs/gd_midiOutput.cpp @@ -31,19 +31,20 @@ #include "../../core/sampleChannel.h" #include "../../core/conf.h" #include "../../core/midiChannel.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" +#include "../../utils/log.h" #include "../elems/ge_mixed.h" -#include "../elems/ge_channel.h" +#include "../elems/channel.h" #include "../elems/ge_midiIoTools.h" #include "../elems/ge_keyboard.h" #include "gd_midiOutput.h" -extern Conf G_Conf; +extern Conf G_Conf; +extern KernelMidi G_KernelMidi; gdMidiOutput::gdMidiOutput(int w, int h) - //: gWindow(300, 64, "Midi Output Setup") : gWindow(w, h, "Midi Output Setup") { } @@ -52,8 +53,9 @@ gdMidiOutput::gdMidiOutput(int w, int h) /* -------------------------------------------------------------------------- */ -void gdMidiOutput::stopMidiLearn(gLearner *learner) { - kernelMidi::stopMidiLearn(); +void gdMidiOutput::stopMidiLearn(gLearner *learner) +{ + G_KernelMidi.stopMidiLearn(); learner->updateValue(); } @@ -61,17 +63,19 @@ void gdMidiOutput::stopMidiLearn(gLearner *learner) { /* -------------------------------------------------------------------------- */ -void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { +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); + gu_log("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); } /* -------------------------------------------------------------------------- */ -void gdMidiOutput::cb_learn(uint32_t msg, void *d) { +void gdMidiOutput::cb_learn(uint32_t msg, void *d) +{ cbData *data = (cbData*) d; gdMidiOutput *window = (gdMidiOutput*) data->window; gLearner *learner = data->learner; @@ -90,7 +94,8 @@ void gdMidiOutput::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutput*)p)->__cb_c /* -------------------------------------------------------------------------- */ -void gdMidiOutput::__cb_close() { +void gdMidiOutput::__cb_close() +{ do_callback(); } @@ -98,7 +103,8 @@ void gdMidiOutput::__cb_close() { /* -------------------------------------------------------------------------- */ -void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p) { +void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p) +{ ((gdMidiOutput*)p)->__cb_enableLightning(); } @@ -190,7 +196,8 @@ void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutp /* -------------------------------------------------------------------------- */ -void gdMidiOutputMidiCh::__cb_enableChanList() { +void gdMidiOutputMidiCh::__cb_enableChanList() +{ enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); } @@ -198,7 +205,8 @@ void gdMidiOutputMidiCh::__cb_enableChanList() { /* -------------------------------------------------------------------------- */ -void gdMidiOutputMidiCh::__cb_close() { +void gdMidiOutputMidiCh::__cb_close() +{ ch->midiOut = enableOut->value(); ch->midiOutChan = chanListOut->value(); ch->midiOutL = enableLightning->value(); @@ -243,7 +251,8 @@ void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampl /* -------------------------------------------------------------------------- */ -void gdMidiOutputSampleCh::__cb_close() { +void gdMidiOutputSampleCh::__cb_close() +{ ch->midiOutL = enableLightning->value(); do_callback(); } diff --git a/src/gui/dialogs/gd_pluginChooser.cpp b/src/gui/dialogs/gd_pluginChooser.cpp index c090caa..d868108 100644 --- a/src/gui/dialogs/gd_pluginChooser.cpp +++ b/src/gui/dialogs/gd_pluginChooser.cpp @@ -30,7 +30,7 @@ #ifdef WITH_VST -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/channel.h" #include "../../core/mixer.h" #include "../../core/conf.h" diff --git a/src/gui/dialogs/gd_pluginList.cpp b/src/gui/dialogs/gd_pluginList.cpp index 433284f..003ca63 100644 --- a/src/gui/dialogs/gd_pluginList.cpp +++ b/src/gui/dialogs/gd_pluginList.cpp @@ -30,16 +30,19 @@ #ifdef WITH_VST -#include "../../utils/gui_utils.h" -#include "../../utils/utils.h" +#include "../../utils/gui.h" +#include "../../utils/fs.h" #include "../../core/conf.h" +#include "../../core/const.h" #include "../../core/graphics.h" #include "../../core/pluginHost.h" #include "../../core/plugin.h" #include "../../core/mixer.h" #include "../../core/channel.h" +#include "../../utils/log.h" +#include "../../utils/string.h" #include "../elems/ge_mixed.h" -#include "../elems/ge_channel.h" +#include "../elems/channel.h" #include "gd_pluginList.h" #include "gd_pluginChooser.h" #include "gd_pluginWindow.h" @@ -51,7 +54,7 @@ extern Conf G_Conf; extern Mixer G_Mixer; extern PluginHost G_PluginHost; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; using std::string; @@ -86,7 +89,7 @@ gdPluginList::gdPluginList(int stackType, Channel *ch) if (stackType == PluginHost::MASTER_IN) label("Master In Plugins"); else { - string l = "Channel " + gItoa(ch->index+1) + " Plugins"; + string l = "Channel " + gu_itoa(ch->index+1) + " Plugins"; copy_label(l.c_str()); } @@ -195,12 +198,12 @@ void gdPluginList::refreshList() { gdPluginListMaster */ if (stackType == PluginHost::MASTER_OUT) { - mainWin->inOut->setMasterFxOutFull( + G_MainWin->inOut->setMasterFxOutFull( G_PluginHost.countPlugins(stackType, ch) > 0); } else if (stackType == PluginHost::MASTER_IN) { - mainWin->inOut->setMasterFxInFull( + G_MainWin->inOut->setMasterFxInFull( G_PluginHost.countPlugins(stackType, ch) > 0); } else { @@ -340,13 +343,13 @@ void gdPlugin::__cb_openPluginWindow() gWindow *w; if (pPlugin->hasEditor()) { if (pPlugin->isEditorOpen()) { - gLog("[gdPlugin::__cb_openPluginWindow] plugin has editor but it's already visible\n"); + gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor but it's already visible\n"); return; } int pwid = pPlugin->getId()+1; - gLog("[gdPlugin::__cb_openPluginWindow] plugin has editor, open window id=%d\n", pwid); + gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor, open window id=%d\n", pwid); if (pParent->hasWindow(pwid)) pParent->delSubWindow(pwid); diff --git a/src/gui/dialogs/gd_pluginWindow.cpp b/src/gui/dialogs/gd_pluginWindow.cpp index cc4348a..0c0be5f 100644 --- a/src/gui/dialogs/gd_pluginWindow.cpp +++ b/src/gui/dialogs/gd_pluginWindow.cpp @@ -31,7 +31,7 @@ #include -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/plugin.h" #include "../elems/ge_mixed.h" #include "gd_pluginWindow.h" diff --git a/src/gui/dialogs/gd_pluginWindowGUI.cpp b/src/gui/dialogs/gd_pluginWindowGUI.cpp index b50b1f4..e8ba698 100644 --- a/src/gui/dialogs/gd_pluginWindowGUI.cpp +++ b/src/gui/dialogs/gd_pluginWindowGUI.cpp @@ -31,7 +31,7 @@ #include "../../utils/log.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/pluginHost.h" #include "../../core/plugin.h" #include "../../core/const.h" @@ -57,7 +57,7 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin) #endif - gLog("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n", + gu_log("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n", (void*) this, (void*) fl_xid(this)); #if defined(__APPLE__) @@ -75,8 +75,6 @@ gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin) int pluginW = pPlugin->getEditorW(); int pluginH = pPlugin->getEditorH(); - printf("w=%d h=%d\n", Fl::w(), Fl::h()); - resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH); Fl::add_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this); @@ -100,7 +98,7 @@ void gdPluginWindowGUI::__cb_close() { Fl::remove_timeout(cb_refresh); pPlugin->closeEditor(); - gLog("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this); + gu_log("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this); } @@ -109,7 +107,7 @@ void gdPluginWindowGUI::__cb_close() void gdPluginWindowGUI::__cb_refresh() { - //gLog("[gdPluginWindowGUI::__cb_refresh] refresh!\n"); + //gu_log("[gdPluginWindowGUI::__cb_refresh] refresh!\n"); G_PluginHost.runDispatchLoop(); Fl::repeat_timeout(GUI_PLUGIN_RATE, cb_refresh, (void*) this); } diff --git a/src/gui/dialogs/gd_warnings.h b/src/gui/dialogs/gd_warnings.h index c2350cf..13d3b4e 100644 --- a/src/gui/dialogs/gd_warnings.h +++ b/src/gui/dialogs/gd_warnings.h @@ -33,7 +33,7 @@ #include #include #include "../elems/ge_mixed.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" void gdAlert(const char *c); diff --git a/src/gui/elems/ge_actionChannel.cpp b/src/gui/elems/actionEditor.cpp similarity index 89% rename from src/gui/elems/ge_actionChannel.cpp rename to src/gui/elems/actionEditor.cpp index 81b453a..4a88413 100644 --- a/src/gui/elems/ge_actionChannel.cpp +++ b/src/gui/elems/actionEditor.cpp @@ -31,36 +31,37 @@ #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" #include "../../utils/log.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_actionEditor.h" #include "ge_keyboard.h" -#include "ge_actionChannel.h" +#include "actionEditor.h" -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; extern Mixer G_Mixer; extern Conf G_Conf; +extern Recorder G_Recorder; /* -------------------------------------------------------------------------- */ -gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch) - : gActionWidget(x, y, 200, 40, pParent), - ch (ch), - selected (NULL) +geActionEditor::geActionEditor(int x, int y, gdActionEditor *pParent, SampleChannel *ch) + : geBaseActionEditor(x, y, 200, 40, pParent), + ch (ch), + selected (NULL) { size(pParent->totalWidth, h()); /* add actions when the window opens. Their position is zoom-based; * each frame is / 2 because we don't care about stereo infos. */ - for (unsigned i=0; ichan->index); @@ -73,7 +74,7 @@ gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChan - not of types ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN */ if ((action->chan != pParent->chan->index) || - (recorder::frames.at(i) > G_Mixer.totalFrames) || + (G_Recorder.frames.at(i) > G_Mixer.totalFrames) || (action->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS) || (action->type == ACTION_KEYREL && ch->mode == SINGLE_PRESS) || (action->type & ~(ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN)) @@ -101,7 +102,7 @@ gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChan /* -------------------------------------------------------------------------- */ -gAction *gActionChannel::getSelectedAction() +gAction *geActionEditor::getSelectedAction() { for (int i=0; ix(); @@ -116,7 +117,7 @@ gAction *gActionChannel::getSelectedAction() /* -------------------------------------------------------------------------- */ -void gActionChannel::updateActions() +void geActionEditor::updateActions() { /* when zooming, don't delete and re-add actions, just MOVE them. This * function shifts the action by a zoom factor. Those singlepress are @@ -143,7 +144,7 @@ void gActionChannel::updateActions() /* -------------------------------------------------------------------------- */ -void gActionChannel::draw() +void geActionEditor::draw() { /* draw basic boundaries (+ beat bars) and hide the unused area. Then * draw the children (the actions) */ @@ -166,7 +167,7 @@ void gActionChannel::draw() /* -------------------------------------------------------------------------- */ -int gActionChannel::handle(int e) +int geActionEditor::handle(int e) { int ret = Fl_Group::handle(e); @@ -289,13 +290,13 @@ int gActionChannel::handle(int e) y()+4, // y h()-8, // h fx, // frame_a - recorder::frames.size()-1, // n. of actions recorded + G_Recorder.frames.size()-1, // n. of actions recorded pParent, // pParent window pointer ch, // pointer to SampleChannel true, // record = true: record it! pParent->getActionType()); // type of action add(a); - mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); // mainWindow update + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)ch->guiChannel); // mainWindow update redraw(); ret = 1; } @@ -313,7 +314,7 @@ int gActionChannel::handle(int e) a->delAction(); remove(a); delete a; - mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); redraw(); ret = 1; } @@ -407,7 +408,7 @@ int gActionChannel::handle(int e) /* -------------------------------------------------------------------------- */ -bool gActionChannel::actionCollides(int frame) +bool geActionEditor::actionCollides(int frame) { /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't * overlap the head (frame) of the new one. First the general case, yet. */ @@ -465,14 +466,14 @@ gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEdito * key_release is associated. */ if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) { - recorder::action *a2 = NULL; - recorder::getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2); + Recorder::action *a2 = NULL; + G_Recorder.getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2); if (a2) { frame_b = a2->frame; w((frame_b - frame_a)/parent->zoom); } else - gLog("[gActionChannel] frame_b not found! [%d:???]\n", frame_a); + gu_log("[geActionEditor] frame_b not found! [%d:???]\n", frame_a); /* a singlepress action narrower than 8 pixel is useless. So check it. * Warning: if an action is 8 px narrow, it has no body space to drag @@ -490,7 +491,7 @@ gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEdito void gAction::draw() { int color; - if (selected) /// && gActionChannel !disabled + if (selected) /// && geActionEditor !disabled color = COLOR_BD_1; else color = COLOR_BG_2; @@ -581,16 +582,16 @@ void gAction::addAction() * (b) is just a graphical and meaningless point. */ if (ch->mode == SINGLE_PRESS) { - recorder::rec(parent->chan->index, ACTION_KEYPRESS, frame_a); - recorder::rec(parent->chan->index, ACTION_KEYREL, frame_a+4096); - //gLog("action added, [%d, %d]\n", frame_a, frame_a+4096); + G_Recorder.rec(parent->chan->index, ACTION_KEYPRESS, frame_a); + G_Recorder.rec(parent->chan->index, ACTION_KEYREL, frame_a+4096); + //gu_log("action added, [%d, %d]\n", frame_a, frame_a+4096); } else { - recorder::rec(parent->chan->index, parent->getActionType(), frame_a); - //gLog("action added, [%d]\n", frame_a); + G_Recorder.rec(parent->chan->index, parent->getActionType(), frame_a); + //gu_log("action added, [%d]\n", frame_a); } - recorder::sortActions(); + G_Recorder.sortActions(); index++; // important! } @@ -605,11 +606,11 @@ void gAction::delAction() * actions. */ if (ch->mode == SINGLE_PRESS) { - recorder::deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false); - recorder::deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false); + G_Recorder.deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false); + G_Recorder.deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false); } else - recorder::deleteAction(parent->chan->index, frame_a, type, false); + G_Recorder.deleteAction(parent->chan->index, frame_a, type, false); /* restore the initial cursor shape, in case you delete an action and * the double arrow (for resizing) is displayed */ @@ -640,14 +641,14 @@ void gAction::moveAction(int frame_a) if (this->frame_a % 2 != 0) this->frame_a++; - recorder::rec(parent->chan->index, type, this->frame_a); + G_Recorder.rec(parent->chan->index, type, this->frame_a); if (ch->mode == SINGLE_PRESS) { frame_b = xToFrame_b(); - recorder::rec(parent->chan->index, ACTION_KEYREL, frame_b); + G_Recorder.rec(parent->chan->index, ACTION_KEYREL, frame_b); } - recorder::sortActions(); + G_Recorder.sortActions(); } diff --git a/src/gui/elems/ge_actionChannel.h b/src/gui/elems/actionEditor.h similarity index 95% rename from src/gui/elems/ge_actionChannel.h rename to src/gui/elems/actionEditor.h index 051feea..56f0ce8 100644 --- a/src/gui/elems/ge_actionChannel.h +++ b/src/gui/elems/actionEditor.h @@ -33,10 +33,10 @@ #include #include -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/mixer.h" #include "../../core/recorder.h" -#include "ge_actionWidget.h" +#include "baseActionEditor.h" class gAction : public Fl_Box @@ -90,7 +90,7 @@ public: /* -------------------------------------------------------------------------- */ -class gActionChannel : public gActionWidget +class geActionEditor : public geBaseActionEditor { private: @@ -130,7 +130,7 @@ private: public: - gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch); + geActionEditor(int x, int y, gdActionEditor *pParent, class SampleChannel *ch); void draw(); int handle(int e); void updateActions(); diff --git a/src/gui/elems/ge_actionWidget.cpp b/src/gui/elems/baseActionEditor.cpp similarity index 89% rename from src/gui/elems/ge_actionWidget.cpp rename to src/gui/elems/baseActionEditor.cpp index 562a591..bc7a412 100644 --- a/src/gui/elems/ge_actionWidget.cpp +++ b/src/gui/elems/baseActionEditor.cpp @@ -1,4 +1,4 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * @@ -6,7 +6,7 @@ * * pParent class of any widget inside the action editor. * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -26,33 +26,34 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include #include "../../core/mixer.h" #include "../dialogs/gd_actionEditor.h" -#include "ge_actionWidget.h" +#include "baseActionEditor.h" #include "ge_mixed.h" extern Mixer G_Mixer; -gActionWidget::gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent) +geBaseActionEditor::geBaseActionEditor(int x, int y, int w, int h, + gdActionEditor *pParent) : Fl_Group(x, y, w, h), pParent(pParent) {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -gActionWidget::~gActionWidget() {} +geBaseActionEditor::~geBaseActionEditor() {} -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gActionWidget::baseDraw(bool clear) { +void geBaseActionEditor::baseDraw(bool clear) { /* clear the screen */ diff --git a/src/gui/elems/ge_actionWidget.h b/src/gui/elems/baseActionEditor.h similarity index 84% rename from src/gui/elems/ge_actionWidget.h rename to src/gui/elems/baseActionEditor.h index 1536b29..49c74b1 100644 --- a/src/gui/elems/ge_actionWidget.h +++ b/src/gui/elems/baseActionEditor.h @@ -1,12 +1,12 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionWidget * - * parent class of any widget inside the action editor. + * parent class of any tool inside the action editor. * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -26,7 +26,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef __GE_ACTIONWIDGET_H__ @@ -37,17 +37,19 @@ #include "../../core/const.h" -class gActionWidget : public Fl_Group { - +class geBaseActionEditor : public Fl_Group +{ protected: + class gdActionEditor *pParent; void baseDraw(bool clear=true); public: + virtual void updateActions() = 0; - gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent); - ~gActionWidget(); + geBaseActionEditor(int x, int y, int w, int h, gdActionEditor *pParent); + ~geBaseActionEditor(); }; #endif diff --git a/src/gui/elems/ge_channel.cpp b/src/gui/elems/channel.cpp similarity index 51% rename from src/gui/elems/ge_channel.cpp rename to src/gui/elems/channel.cpp index 63dd719..a33f121 100644 --- a/src/gui/elems/ge_channel.cpp +++ b/src/gui/elems/channel.cpp @@ -29,41 +29,107 @@ #include "../../core/mixer.h" #include "../../core/conf.h" +#include "../../core/channel.h" #include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" -#include "../../core/channel.h" -#include "../../core/wave.h" -#include "../../core/sampleChannel.h" -#include "../../core/midiChannel.h" -#include "../../glue/glue.h" -#include "../../utils/gui_utils.h" +#include "../../core/pluginHost.h" +#include "../../utils/gui.h" +#include "../../glue/channel.h" +#include "../../glue/main.h" #include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_keyGrabber.h" -#include "../dialogs/gd_midiInput.h" -#include "../dialogs/gd_editor.h" -#include "../dialogs/gd_actionEditor.h" -#include "../dialogs/gd_warnings.h" -#include "../dialogs/gd_browser.h" -#include "../dialogs/gd_midiOutput.h" -#include "ge_keyboard.h" -#include "ge_channel.h" -#include "ge_sampleChannel.h" +#include "../dialogs/gd_pluginList.h" +#include "ge_column.h" +#include "channelButton.h" +#include "channel.h" extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; + + +geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch) + : Fl_Group(X, Y, W, H, NULL), + ch (ch), + type (type) +{ +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::cb_arm(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_arm(); } +void geChannel::cb_mute(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_mute(); } +void geChannel::cb_solo(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_solo(); } +void geChannel::cb_changeVol(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_changeVol(); } +#ifdef WITH_VST +void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_openFxWindow(); } +#endif + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_arm() +{ + glue_toggleArm(ch, true); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_mute() +{ + glue_setMute(ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_solo() +{ + solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); +} + + +/* -------------------------------------------------------------------------- */ + + +void geChannel::__cb_changeVol() +{ + glue_setChanVol(ch, vol->value()); +} -gChannel::gChannel(int X, int Y, int W, int H, int type) - : Fl_Group(X, Y, W, H, NULL), type(type) {} +/* -------------------------------------------------------------------------- */ + + +#ifdef WITH_VST +void geChannel::__cb_openFxWindow() +{ + gu_openSubWindow(G_MainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); +} +#endif /* -------------------------------------------------------------------------- */ -int gChannel::getColumnIndex() +int geChannel::keyPress(int e) +{ + return handleKey(e, ch->key); +} + + +/* -------------------------------------------------------------------------- */ + + + +int geChannel::getColumnIndex() { return ((gColumn*)parent())->getIndex(); } @@ -72,7 +138,7 @@ int gChannel::getColumnIndex() /* -------------------------------------------------------------------------- */ -void gChannel::blink() +void geChannel::blink() { if (gu_getBlinker() > 6) mainButton->setPlayMode(); @@ -84,10 +150,11 @@ void gChannel::blink() /* -------------------------------------------------------------------------- */ -void gChannel::setColorsByStatus(int playStatus, int recStatus) +void geChannel::setColorsByStatus(int playStatus, int recStatus) { switch (playStatus) { case STATUS_OFF: + case STATUS_EMPTY: mainButton->setDefaultMode(); button->imgOn = channelPlay_xpm; button->imgOff = channelStop_xpm; @@ -121,7 +188,40 @@ void gChannel::setColorsByStatus(int playStatus, int recStatus) /* -------------------------------------------------------------------------- */ -int gChannel::handleKey(int e, int key) +void geChannel::packWidgets() +{ + /* Count visible widgets and resize mainButton according to how many widgets + are visible. */ + + int visibles = 0; + for (int i=0; isize(20, 20); // also normalize widths + if (child(i)->visible()) + visibles++; + } + mainButton->size(w() - ((visibles - 1) * (24)), 20); // -1: exclude itself + + /* Reposition everything else */ + + for (int i=1, p=0; ivisible()) + continue; + for (int k=i-1; k>=0; k--) // Get the first visible item prior to i + if (child(k)->visible()) { + p = k; + break; + } + child(i)->position(child(p)->x() + child(p)->w() + 4, y()); + } + + init_sizes(); // Resets the internal array of widget sizes and positions +} + + +/* -------------------------------------------------------------------------- */ + + +int geChannel::handleKey(int e, int key) { int ret; if (e == FL_KEYDOWN && button->value()) // key already pressed! skip it diff --git a/src/gui/elems/ge_channel.h b/src/gui/elems/channel.h similarity index 60% rename from src/gui/elems/ge_channel.h rename to src/gui/elems/channel.h index e0c99ac..33dc00d 100644 --- a/src/gui/elems/ge_channel.h +++ b/src/gui/elems/channel.h @@ -31,30 +31,42 @@ #define GE_CHANNEL_H -#include -#include -#include -#include "ge_mixed.h" +#include -class gChannel : public Fl_Group +class geChannel : public Fl_Group { protected: - /* define some breakpoints for dynamic resize */ + /* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of + pixels to shrink sampleButton. */ #ifdef WITH_VST - static const int BREAK_READ_ACTIONS = 212; - static const int BREAK_MODE_BOX = 188; - static const int BREAK_FX = 164; - static const int BREAK_DELTA = 120; + static const int BREAK_READ_ACTIONS = 240; + static const int BREAK_MODE_BOX = 216; + static const int BREAK_FX = 192; + static const int BREAK_ARM = 168; #else - static const int BREAK_READ_ACTIONS = 188; - static const int BREAK_MODE_BOX = 164; - static const int BREAK_FX = 140; - static const int BREAK_DELTA = 96; + static const int BREAK_READ_ACTIONS = 216; + static const int BREAK_MODE_BOX = 192; + static const int BREAK_ARM = 168; +#endif + + static void cb_arm (Fl_Widget *v, void *p); + static void cb_mute (Fl_Widget *v, void *p); + static void cb_solo (Fl_Widget *v, void *p); + static void cb_changeVol (Fl_Widget *v, void *p); +#ifdef WITH_VST + static void cb_openFxWindow(Fl_Widget *v, void *p); +#endif + + inline void __cb_mute(); + inline void __cb_arm(); + inline void __cb_solo(); + inline void __cb_changeVol(); +#ifdef WITH_VST + inline void __cb_openFxWindow(); #endif - static const int BREAK_UNIT = 24; /* blink * blink button when channel is in wait/ending status. */ @@ -71,9 +83,14 @@ protected: int handleKey(int e, int key); + /* packWidgets + Spread widgets across available space. */ + + void packWidgets(); + public: - gChannel(int x, int y, int w, int h, int type); + geChannel(int x, int y, int w, int h, int type, class Channel *ch); /* reset * reset channel to initial status. */ @@ -94,7 +111,7 @@ public: /* keypress * what to do when the corresponding key is pressed. */ - virtual int keyPress(int event) = 0; + int keyPress(int event); /* getColumnIndex * return the numeric index of the column in which this channel is @@ -102,14 +119,17 @@ public: int getColumnIndex(); - class gButton *button; - class gStatus *status; - class gChannelButton *mainButton; - class gDial *vol; - class gClick *mute; - class gClick *solo; + class Channel *ch; + + class gButton *button; + class gStatus *status; + class gClick *arm; + class geChannelButton *mainButton; + class gClick *mute; + class gClick *solo; + class gDial *vol; #ifdef WITH_VST - class gFxButton *fx; + class gFxButton *fx; #endif int type; diff --git a/src/gui/elems/ge_channelButton.cpp b/src/gui/elems/channelButton.cpp similarity index 85% rename from src/gui/elems/ge_channelButton.cpp rename to src/gui/elems/channelButton.cpp index ab6e306..69d262d 100644 --- a/src/gui/elems/ge_channelButton.cpp +++ b/src/gui/elems/channelButton.cpp @@ -28,21 +28,21 @@ #include "../../core/const.h" -#include "../../utils/utils.h" -#include "ge_channelButton.h" +#include "../../utils/fs.h" +#include "channelButton.h" using std::string; -gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l) +geChannelButton::geChannelButton(int x, int y, int w, int h, const char *l) : gClick(x, y, w, h, l), key("") {} /* -------------------------------------------------------------------------- */ -void gChannelButton::setKey(const string &k) +void geChannelButton::setKey(const string &k) { key = k; } @@ -51,7 +51,7 @@ void gChannelButton::setKey(const string &k) /* -------------------------------------------------------------------------- */ -void gChannelButton::setKey(int k) +void geChannelButton::setKey(int k) { if (k == 0) key = ""; @@ -66,7 +66,7 @@ void gChannelButton::setKey(int k) /* -------------------------------------------------------------------------- */ -void gChannelButton::draw() +void geChannelButton::draw() { gClick::draw(); @@ -88,7 +88,7 @@ void gChannelButton::draw() /* -------------------------------------------------------------------------- */ -void gChannelButton::setInputRecordMode() +void geChannelButton::setInputRecordMode() { bgColor0 = COLOR_BG_3; } @@ -97,7 +97,7 @@ void gChannelButton::setInputRecordMode() /* -------------------------------------------------------------------------- */ -void gChannelButton::setActionRecordMode() +void geChannelButton::setActionRecordMode() { bgColor0 = COLOR_BG_4; txtColor = COLOR_TEXT_0; @@ -107,7 +107,7 @@ void gChannelButton::setActionRecordMode() /* -------------------------------------------------------------------------- */ -void gChannelButton::setDefaultMode(const char *l) +void geChannelButton::setDefaultMode(const char *l) { bgColor0 = COLOR_BG_0; bdColor = COLOR_BD_0; @@ -120,7 +120,7 @@ void gChannelButton::setDefaultMode(const char *l) /* -------------------------------------------------------------------------- */ -void gChannelButton::setPlayMode() +void geChannelButton::setPlayMode() { bgColor0 = COLOR_BG_2; bdColor = COLOR_BD_1; @@ -131,7 +131,7 @@ void gChannelButton::setPlayMode() /* -------------------------------------------------------------------------- */ -void gChannelButton::setEndingMode() +void geChannelButton::setEndingMode() { bgColor0 = COLOR_BD_0; } diff --git a/src/gui/elems/ge_channelButton.h b/src/gui/elems/channelButton.h similarity index 93% rename from src/gui/elems/ge_channelButton.h rename to src/gui/elems/channelButton.h index 9a1718d..da08cd8 100644 --- a/src/gui/elems/ge_channelButton.h +++ b/src/gui/elems/channelButton.h @@ -37,7 +37,7 @@ using std::string; -class gChannelButton : public gClick +class geChannelButton : public gClick { private: @@ -45,7 +45,7 @@ private: public: - gChannelButton(int x, int y, int w, int h, const char *l=0); + geChannelButton(int x, int y, int w, int h, const char *l=0); virtual int handle(int e) = 0; diff --git a/src/gui/elems/ge_envelopeChannel.cpp b/src/gui/elems/envelopeEditor.cpp similarity index 81% rename from src/gui/elems/ge_envelopeChannel.cpp rename to src/gui/elems/envelopeEditor.cpp index b6be16e..7ade209 100644 --- a/src/gui/elems/ge_envelopeChannel.cpp +++ b/src/gui/elems/envelopeEditor.cpp @@ -37,16 +37,22 @@ #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" #include "ge_keyboard.h" -#include "ge_envelopeChannel.h" +#include "envelopeEditor.h" extern Mixer G_Mixer; -extern gdMainWindow *mainWin; - - -gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l) - : gActionWidget(x, y, 200, 80, pParent), l(l), type(type), range(range), - selectedPoint(-1), draggedPoint(-1) +extern Recorder G_Recorder; +extern gdMainWindow *G_MainWin; + + +geEnvelopeEditor::geEnvelopeEditor(int x, int y, gdActionEditor *pParent, + int type, int range, const char *l) + : geBaseActionEditor(x, y, 200, 80, pParent), + l (l), + type (type), + range (range), + selectedPoint (-1), + draggedPoint (-1) { size(pParent->totalWidth, h()); } @@ -55,7 +61,7 @@ gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int ty /* ------------------------------------------------------------------ */ -gEnvelopeChannel::~gEnvelopeChannel() { +geEnvelopeEditor::~geEnvelopeEditor() { clearPoints(); } @@ -63,7 +69,7 @@ gEnvelopeChannel::~gEnvelopeChannel() { /* ------------------------------------------------------------------ */ -void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int py) { +void geEnvelopeEditor::addPoint(int frame, int iValue, float fValue, int px, int py) { point p; p.frame = frame; p.iValue = iValue; @@ -77,7 +83,7 @@ void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int /* ------------------------------------------------------------------ */ -void gEnvelopeChannel::updateActions() { +void geEnvelopeEditor::updateActions() { for (unsigned i=0; izoom; } @@ -86,7 +92,7 @@ void gEnvelopeChannel::updateActions() { /* ------------------------------------------------------------------ */ -void gEnvelopeChannel::draw() { +void geEnvelopeEditor::draw() { baseDraw(); @@ -128,7 +134,7 @@ void gEnvelopeChannel::draw() { /* ------------------------------------------------------------------ */ -int gEnvelopeChannel::handle(int e) { +int geEnvelopeEditor::handle(int e) { /* Adding an action: no further checks required, just record it on frame * mx*pParent->zoom. Deleting action is trickier: find the active @@ -185,9 +191,9 @@ int gEnvelopeChannel::handle(int e) { if (points.size() == 0) { addPoint(0, 0, 1.0f, 0, 1); - recorder::rec(pParent->chan->index, type, 0, 0, 1.0f); + G_Recorder.rec(pParent->chan->index, type, 0, 0, 1.0f); addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1); - recorder::rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f); + G_Recorder.rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f); } /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */ @@ -195,14 +201,14 @@ int gEnvelopeChannel::handle(int e) { int frame = mx * pParent->zoom; float value = (my - h() + 8) / (float) (1 - h() + 8); addPoint(frame, 0, value, mx, my); - recorder::rec(pParent->chan->index, type, frame, 0, value); - recorder::sortActions(); + G_Recorder.rec(pParent->chan->index, type, frame, 0, value); + G_Recorder.sortActions(); sortPoints(); } else { /// TODO } - mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow redraw(); } } @@ -212,15 +218,15 @@ int gEnvelopeChannel::handle(int e) { if (selectedPoint != -1) { if (selectedPoint == 0 || (unsigned) selectedPoint == points.size()-1) { - recorder::clearAction(pParent->chan->index, type); + G_Recorder.clearAction(pParent->chan->index, type); points.clear(); } else { - recorder::deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false); - recorder::sortActions(); + G_Recorder.deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false); + G_Recorder.sortActions(); points.erase(points.begin() + selectedPoint); } - mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow redraw(); } } @@ -233,7 +239,7 @@ int gEnvelopeChannel::handle(int e) { if (draggedPoint != -1) { if (points.at(draggedPoint).x == previousXPoint) { - //gLog("nothing to do\n"); + //gu_log("nothing to do\n"); } else { int newFrame = points.at(draggedPoint).x * pParent->zoom; @@ -253,17 +259,17 @@ int gEnvelopeChannel::handle(int e) { /* delete previous point and record a new one */ - recorder::deleteAction(pParent->chan->index, points.at(draggedPoint).frame, type, false); + G_Recorder.deleteAction(pParent->chan->index, points.at(draggedPoint).frame, type, false); if (range == RANGE_FLOAT) { float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8); - recorder::rec(pParent->chan->index, type, newFrame, 0, value); + G_Recorder.rec(pParent->chan->index, type, newFrame, 0, value); } else { /// TODO } - recorder::sortActions(); + G_Recorder.sortActions(); points.at(draggedPoint).frame = newFrame; draggedPoint = -1; selectedPoint = -1; @@ -328,7 +334,7 @@ int gEnvelopeChannel::handle(int e) { /* ------------------------------------------------------------------ */ -int gEnvelopeChannel::verticalPoint(const point &p) { +int geEnvelopeEditor::verticalPoint(const point &p) { for (unsigned i=0; i points.at(i).x) @@ -361,7 +367,7 @@ void gEnvelopeChannel::sortPoints() { /* ------------------------------------------------------------------ */ -int gEnvelopeChannel::getSelectedPoint() { +int geEnvelopeEditor::getSelectedPoint() { /* point is a 7x7 dot */ @@ -379,11 +385,11 @@ int gEnvelopeChannel::getSelectedPoint() { /* ------------------------------------------------------------------ */ -void gEnvelopeChannel::fill() { +void geEnvelopeEditor::fill() { points.clear(); - for (unsigned i=0; itype == type && a->chan == pParent->chan->index) { if (range == RANGE_FLOAT) addPoint( diff --git a/src/gui/elems/ge_envelopeChannel.h b/src/gui/elems/envelopeEditor.h similarity index 93% rename from src/gui/elems/ge_envelopeChannel.h rename to src/gui/elems/envelopeEditor.h index 8afe11b..f7dade4 100644 --- a/src/gui/elems/ge_envelopeChannel.h +++ b/src/gui/elems/envelopeEditor.h @@ -36,14 +36,14 @@ #include #include #include -#include "../../utils/utils.h" -#include "ge_actionWidget.h" +#include "../../utils/fs.h" +#include "baseActionEditor.h" using std::vector; -class gEnvelopeChannel : public gActionWidget +class geEnvelopeEditor : public geBaseActionEditor { const char *l; // internal label int type; // type of action @@ -52,7 +52,8 @@ class gEnvelopeChannel : public gActionWidget /* point * a single dot in the graph. x = relative frame, y = relative value */ - struct point { + struct point + { int frame; int iValue; float fValue; @@ -98,8 +99,9 @@ class gEnvelopeChannel : public gActionWidget int verticalPoint(const point &p); public: - gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l); - ~gEnvelopeChannel(); + + geEnvelopeEditor(int x, int y, gdActionEditor *pParent, int type, int range, const char *l); + ~geEnvelopeEditor(); /* addPoint * add a point made of frame+value to internal points[]. */ diff --git a/src/gui/elems/ge_browser.cpp b/src/gui/elems/ge_browser.cpp index be64cc8..9ae3235 100644 --- a/src/gui/elems/ge_browser.cpp +++ b/src/gui/elems/ge_browser.cpp @@ -29,7 +29,7 @@ #include #include "../../core/const.h" -#include "../../utils/utils.h" +#include "../../utils/fs.h" #include "../../utils/string.h" #include "../../utils/log.h" #include "../dialogs/gd_browser.h" @@ -122,7 +122,7 @@ int gBrowser::handle(int e) string gBrowser::getCurrentDir() { - return normalize(gGetRealPath(currentDir)); + return normalize(gu_getRealPath(currentDir)); } @@ -137,7 +137,7 @@ string gBrowser::getSelectedItem(bool fullPath) if (value() == 0) // no rows selected? return current directory return normalize(currentDir); else - return normalize(gGetRealPath(currentDir + G_SLASH + normalize(text(value())))); + return normalize(gu_getRealPath(currentDir + G_SLASH + normalize(text(value())))); } @@ -158,12 +158,14 @@ string gBrowser::normalize(const string &s) { string out = s; - /* our crappy version of Clang doesn't seem to support std::string::back() */ + /* If string ends with G_SLASH, remove it. Don't do it if has length > 1, it + means that the string is just '/'. Note: our crappy version of Clang doesn't + seem to support std::string::back() */ #ifdef __APPLE__ - if (out[out.length() - 1] == G_SLASH) + if (out[out.length() - 1] == G_SLASH && out.length() > 1) #else - if (out.back() == G_SLASH) + if (out.back() == G_SLASH && out.length() > 1) #endif out = out.substr(0, out.size()-1); diff --git a/src/gui/elems/ge_column.cpp b/src/gui/elems/ge_column.cpp index 5f0dc4c..7f8a046 100644 --- a/src/gui/elems/ge_column.cpp +++ b/src/gui/elems/ge_column.cpp @@ -33,16 +33,17 @@ #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" #include "../../glue/channel.h" #include "../../utils/log.h" +#include "../../utils/string.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_warnings.h" #include "../elems/ge_keyboard.h" #include "ge_column.h" -#include "ge_channel.h" -#include "ge_sampleChannel.h" -#include "ge_midiChannel.h" +#include "channel.h" +#include "sampleChannel.h" +#include "midiChannel.h" extern Mixer G_Mixer; @@ -107,13 +108,13 @@ int gColumn::handle(int e) } case FL_PASTE: { // handle actual drop (paste) operation vector paths; - gSplit(Fl::event_text(), "\n", &paths); + gu_split(Fl::event_text(), "\n", &paths); bool fails = false; int result = 0; for (unsigned i=0; iguiChannel); fails = true; @@ -165,7 +166,7 @@ void gColumn::resize(int X, int Y, int W, int H) void gColumn::refreshChannels() { for (int i=1; irefresh(); + ((geChannel*) child(i))->refresh(); } @@ -196,14 +197,14 @@ void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChan /* -------------------------------------------------------------------------- */ -gChannel *gColumn::addChannel(class Channel *ch) +geChannel *gColumn::addChannel(Channel *ch) { int currentY = y() + children() * 24; - gChannel *gch = NULL; + geChannel *gch = NULL; if (ch->type == CHANNEL_SAMPLE) - gch = (gSampleChannel*) new gSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); + gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); else - gch = (gMidiChannel*) new gMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); + gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); add(gch); resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop @@ -216,7 +217,7 @@ gChannel *gColumn::addChannel(class Channel *ch) /* -------------------------------------------------------------------------- */ -void gColumn::deleteChannel(gChannel *gch) +void gColumn::deleteChannel(geChannel *gch) { gch->hide(); remove(gch); @@ -228,7 +229,7 @@ void gColumn::deleteChannel(gChannel *gch) * parameter to skip the operation */ for (int i=0; iposition(gch->x(), y()+(i*24)); } size(w(), children() * 24 + 66); // evil space for drag n drop @@ -241,7 +242,7 @@ void gColumn::deleteChannel(gChannel *gch) void gColumn::__cb_addChannel() { - gLog("[gColumn::__cb_addChannel] index = %d\n", index); + gu_log("[gColumn::__cb_addChannel] index = %d\n", index); int type = openTypeMenu(); if (type) glue_addChannel(index, type); @@ -286,7 +287,7 @@ void gColumn::clear(bool full) else { while (children() >= 2) { // skip "add new channel" btn int i = children()-1; - deleteChannel((gChannel*)child(i)); + deleteChannel((geChannel*)child(i)); } } } @@ -297,9 +298,9 @@ void gColumn::clear(bool full) Channel *gColumn::getChannel(int i) { - gChannel *gch = (gChannel*) child(i); + geChannel *gch = (geChannel*) child(i); if (gch->type == CHANNEL_SAMPLE) - return ((gSampleChannel*) child(i))->ch; + return ((geSampleChannel*) child(i))->ch; else - return ((gMidiChannel*) child(i))->ch; + return ((geMidiChannel*) child(i))->ch; } diff --git a/src/gui/elems/ge_column.h b/src/gui/elems/ge_column.h index 93e8a1c..bcaa2ca 100644 --- a/src/gui/elems/ge_column.h +++ b/src/gui/elems/ge_column.h @@ -59,7 +59,7 @@ public: * add a new channel in this column and set the internal pointer * to channel to 'ch'. */ - class gChannel *addChannel(class Channel *ch); + class geChannel *addChannel(class Channel *ch); /* handle */ @@ -73,7 +73,7 @@ public: /* deleteChannel * remove the channel 'gch' from this column. */ - void deleteChannel(gChannel *gch); + void deleteChannel(geChannel *gch); /* refreshChannels * update channels' graphical statues. Called on each GUI cycle. */ diff --git a/src/gui/elems/ge_controller.cpp b/src/gui/elems/ge_controller.cpp index ed9f738..9ff5f25 100644 --- a/src/gui/elems/ge_controller.cpp +++ b/src/gui/elems/ge_controller.cpp @@ -27,7 +27,8 @@ #include "../../core/graphics.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" +#include "../../glue/io.h" #include "ge_mixed.h" #include "ge_controller.h" @@ -87,7 +88,7 @@ void gController::__cb_rewind() void gController::__cb_play() { - glue_startStopSeq(); + glue_startStopSeq(true); } @@ -96,7 +97,7 @@ void gController::__cb_play() void gController::__cb_recAction() { - glue_startStopActionRec(); + glue_startStopActionRec(true); } @@ -105,7 +106,7 @@ void gController::__cb_recAction() void gController::__cb_recInput() { - glue_startStopInputRec(); + glue_startStopInputRec(true); } @@ -114,7 +115,7 @@ void gController::__cb_recInput() void gController::__cb_metronome() { - glue_startStopMetronome(); + glue_startStopMetronome(true); } diff --git a/src/gui/elems/ge_keyboard.cpp b/src/gui/elems/ge_keyboard.cpp index 5d5fd37..68a8228 100644 --- a/src/gui/elems/ge_keyboard.cpp +++ b/src/gui/elems/ge_keyboard.cpp @@ -33,14 +33,15 @@ #include "../../core/patch_DEPR_.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" +#include "../../glue/io.h" #include "../../utils/log.h" #include "../dialogs/gd_browser.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_warnings.h" -#include "ge_channel.h" -#include "ge_sampleChannel.h" +#include "channel.h" +#include "sampleChannel.h" #include "ge_keyboard.h" @@ -101,7 +102,7 @@ void gKeyboard::init() /* -------------------------------------------------------------------------- */ -void gKeyboard::freeChannel(gChannel *gch) +void gKeyboard::freeChannel(geChannel *gch) { gch->reset(); } @@ -110,7 +111,7 @@ void gKeyboard::freeChannel(gChannel *gch) /* -------------------------------------------------------------------------- */ -void gKeyboard::deleteChannel(gChannel *gch) +void gKeyboard::deleteChannel(geChannel *gch) { for (unsigned i=0; ifind(gch); @@ -125,7 +126,7 @@ void gKeyboard::deleteChannel(gChannel *gch) /* -------------------------------------------------------------------------- */ -void gKeyboard::updateChannel(gChannel *gch) +void gKeyboard::updateChannel(geChannel *gch) { gch->update(); } @@ -180,7 +181,7 @@ void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) /* -------------------------------------------------------------------------- */ -gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) +geChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) { gColumn *col = getColumnByIndex(colIndex); @@ -191,10 +192,10 @@ gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) __cb_addColumn(); col = columns.back(); col->setIndex(colIndex); - gLog("[gKeyboard::addChannel] created new column with index=%d\n", colIndex); + gu_log("[gKeyboard::addChannel] created new column with index=%d\n", colIndex); } - gLog("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex()); + gu_log("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex()); return col->addChannel(ch); } @@ -223,6 +224,8 @@ gColumn *gKeyboard::getColumnByIndex(int index) /* -------------------------------------------------------------------------- */ +/* TODO - the following event handling for play, stop, rewind, start rec and +so on should be moved to the proper widget: gdMainWindow or (better) geController. */ int gKeyboard::handle(int e) { @@ -254,13 +257,13 @@ int gKeyboard::handle(int e) } else if (Fl::event_key() == FL_Enter && !enterPressed) { enterPressed = true; - glue_startStopActionRec(); + glue_startStopActionRec(false); // update gui ret = 1; break; } else if (Fl::event_key() == ' ' && !spacePressed) { spacePressed = true; - G_Mixer.running ? glue_stopSeq() : glue_startSeq(); // TODO - glue_startStopSeq, no core logic here + glue_startStopSeq(false); // update gui ret = 1; break; } @@ -282,7 +285,7 @@ int gKeyboard::handle(int e) for (unsigned i=0; ichildren(); k++) - ret &= ((gChannel*)columns.at(i)->child(k))->keyPress(e); + ret &= ((geChannel*)columns.at(i)->child(k))->keyPress(e); break; } } @@ -306,12 +309,12 @@ void gKeyboard::clear() /* -------------------------------------------------------------------------- */ -void gKeyboard::setChannelWithActions(gSampleChannel *gch) +void gKeyboard::setChannelWithActions(geSampleChannel *gch) { if (gch->ch->hasActions) - gch->addActionButton(); + gch->showActionButton(); else - gch->delActionButton(); + gch->hideActionButton(); } @@ -369,7 +372,7 @@ void gKeyboard::__cb_addColumn(int width) addColumnBtn->position(colxw + gap, y()); redraw(); - gLog("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", + gu_log("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", gc->getIndex(), width, columns.size(), addColumnBtn->x()); /* recompute col indexes */ diff --git a/src/gui/elems/ge_keyboard.h b/src/gui/elems/ge_keyboard.h index 967758c..c5558b9 100644 --- a/src/gui/elems/ge_keyboard.h +++ b/src/gui/elems/ge_keyboard.h @@ -39,7 +39,7 @@ #include #include "../elems/ge_column.h" #include "../../core/const.h" -#include "../../utils/utils.h" +#include "../../utils/fs.h" using std::vector; @@ -87,12 +87,12 @@ public: void init(); /* addChannel - * add a new channel to gChannels. Used by callbacks and during - * patch loading. Requires Channel (and not gChannel). If build is + * add a new channel to geChannels. Used by callbacks and during + * patch loading. Requires Channel (and not geChannel). If build is * set to true, also generate the corresponding column if column (index) does * not exist yet. */ - gChannel *addChannel(int column, class Channel *ch, bool build=false); + class geChannel *addChannel(int column, class Channel *ch, bool build=false); /* addColumn * add a new column to the top of the stack. */ @@ -100,21 +100,21 @@ public: void addColumn(int width=380); /* deleteChannel - * delete a channel from gChannels<> where gChannel->ch == ch and remove + * delete a channel from geChannels<> where geChannel->ch == ch and remove * it from the stack. */ - void deleteChannel(gChannel *gch); + void deleteChannel(geChannel *gch); /* freeChannel - * free a channel from gChannels<> where gChannel->ch == ch. No channels + * free a channel from geChannels<> where geChannel->ch == ch. No channels * are deleted */ - void freeChannel(gChannel *gch); + void freeChannel(geChannel *gch); /* updateChannel * wrapper function to call gch->update(). */ - void updateChannel(gChannel *gch); + void updateChannel(geChannel *gch); /* organizeColumns * reorganize columns layout by removing empty gaps. */ @@ -144,7 +144,7 @@ public: /* setChannelWithActions * add 'R' button if channel has actions, and set recorder to active. */ - void setChannelWithActions(class gSampleChannel *gch); + void setChannelWithActions(class geSampleChannel *gch); /* printChannelMessage * given any output by glue_loadChannel, print the message on screen diff --git a/src/gui/elems/ge_midiIoTools.cpp b/src/gui/elems/ge_midiIoTools.cpp index 9057f3f..8c20101 100644 --- a/src/gui/elems/ge_midiIoTools.cpp +++ b/src/gui/elems/ge_midiIoTools.cpp @@ -27,11 +27,15 @@ * -------------------------------------------------------------------------- */ -#include "ge_midiIoTools.h" #include "ge_mixed.h" +#include "ge_midiIoTools.h" + + +extern KernelMidi G_KernelMidi; -gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param) +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) @@ -98,8 +102,8 @@ void gLearner::__cb_button() { cbData *data = (cbData*) malloc(sizeof(cbData)); data->window = (gdMidiInput*) parent(); // parent = gdMidiGrabberChannel data->learner = this; - kernelMidi::startMidiLearn(callback, (void*)data); + G_KernelMidi.startMidiLearn(callback, (void*)data); } else - kernelMidi::stopMidiLearn(); + G_KernelMidi.stopMidiLearn(); } diff --git a/src/gui/elems/ge_midiIoTools.h b/src/gui/elems/ge_midiIoTools.h index 2a795e1..0712937 100644 --- a/src/gui/elems/ge_midiIoTools.h +++ b/src/gui/elems/ge_midiIoTools.h @@ -31,12 +31,14 @@ #define GE_LEARNER_H -#include #include #include "../../core/kernelMidi.h" #include "../dialogs/gd_midiInput.h" +extern KernelMidi G_KernelMidi; + + class gLearner : public Fl_Group { private: @@ -46,7 +48,7 @@ private: * uint32_t msg - MIDI message * void *data - extra data */ - kernelMidi::cb_midiLearn *callback; + KernelMidi::cb_midiLearn *callback; class gBox *text; class gClick *value; @@ -64,7 +66,7 @@ public: uint32_t *param; - gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param); + gLearner(int x, int y, int w, const char *l, KernelMidi::cb_midiLearn *cb, uint32_t *param); void updateValue(); }; diff --git a/src/gui/elems/ge_mixed.cpp b/src/gui/elems/ge_mixed.cpp index 60abf9e..0969a8a 100644 --- a/src/gui/elems/ge_mixed.cpp +++ b/src/gui/elems/ge_mixed.cpp @@ -34,7 +34,7 @@ #include "../../core/recorder.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../dialogs/gd_mainWindow.h" #include "ge_mixed.h" @@ -452,7 +452,7 @@ gResizerBar::gResizerBar(int X,int Y,int W,int H, bool vertical) /* gResizerBar::~gResizerBar() { - gLog("------ resizerbar %p destroyed\n", (void*)this); + gu_log("------ resizerbar %p destroyed\n", (void*)this); } */ diff --git a/src/gui/elems/ge_mixed.h b/src/gui/elems/ge_mixed.h index b41be44..d454497 100644 --- a/src/gui/elems/ge_mixed.h +++ b/src/gui/elems/ge_mixed.h @@ -120,6 +120,7 @@ public: /* gButton * exactly as gClick but with a unique id inside of it. Used for the buttons in * channels and for FXs. */ + /* TODO - is this really useful? */ class gButton : public gClick { diff --git a/src/gui/elems/ge_modeBox.cpp b/src/gui/elems/ge_modeBox.cpp index 27afbea..4a6915b 100644 --- a/src/gui/elems/ge_modeBox.cpp +++ b/src/gui/elems/ge_modeBox.cpp @@ -27,7 +27,7 @@ * -------------------------------------------------------------------------- */ -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" #include "../../core/graphics.h" #include "../../core/sampleChannel.h" #include "../../core/const.h" diff --git a/src/gui/elems/ge_pianoRoll.cpp b/src/gui/elems/ge_pianoRoll.cpp deleted file mode 100644 index bd3dd5b..0000000 --- a/src/gui/elems/ge_pianoRoll.cpp +++ /dev/null @@ -1,730 +0,0 @@ -/* --------------------------------------------------------------------- - * - * Giada - Your Hardcore Loopmachine - * - * ge_pianoRoll - * - * --------------------------------------------------------------------- - * - * Copyright (C) 2010-2016 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 "../../core/channel.h" -#include "../../core/midiChannel.h" -#include "../../core/const.h" -#include "../../core/kernelMidi.h" -#include "../../core/conf.h" -#include "../../utils/log.h" -#include "../dialogs/gd_mainWindow.h" -#include "../dialogs/gd_actionEditor.h" -#include "ge_pianoRoll.h" - - -extern gdMainWindow *mainWin; -extern Mixer G_Mixer; -extern Conf G_Conf; - - -gPianoRollContainer::gPianoRollContainer(int x, int y, class gdActionEditor *pParent) - : Fl_Scroll(x, y, 200, 422), pParent(pParent) -{ - size(pParent->totalWidth, G_Conf.pianoRollH); - pianoRoll = new gPianoRoll(x, y, pParent->totalWidth, pParent); -} - - -/* ------------------------------------------------------------------ */ - - -gPianoRollContainer::~gPianoRollContainer() { - clear(); - G_Conf.pianoRollH = h(); - G_Conf.pianoRollY = pianoRoll->y(); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRollContainer::updateActions() { - pianoRoll->updateActions(); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRollContainer::draw() { - - pianoRoll->size(this->w(), pianoRoll->h()); /// <--- not optimal - - /* clear background */ - - fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN); - - /* clip pianoRoll to pianoRollContainer size */ - - fl_push_clip(x(), y(), w(), h()); - draw_child(*pianoRoll); - fl_pop_clip(); - - fl_color(COLOR_BD_0); - fl_line_style(0); - fl_rect(x(), y(), pParent->totalWidth, h()); -} - - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -gPianoRoll::gPianoRoll(int X, int Y, int W, class gdActionEditor *pParent) - : gActionWidget(X, Y, W, 40, pParent) -{ - resizable(NULL); // don't resize children (i.e. pianoItem) - size(W, (MAX_NOTES+1) * CELL_H); // 128 MIDI channels * 15 px height - - if (G_Conf.pianoRollY == -1) - position(x(), y()-(h()/2)); // center - else - position(x(), G_Conf.pianoRollY); - - drawSurface1(); - drawSurface2(); - - /* add actions when the window is opened. Position is zoom-based. MIDI - * actions come always in pair: start + end. */ - - recorder::sortActions(); - - recorder::action *a2 = NULL; - recorder::action *prev = NULL; - - for (unsigned i=0; i than the grey area */ - /** FIXME - can we move this to the outer cycle? */ - - if (recorder::frames.at(i) > G_Mixer.totalFrames) - continue; - - recorder::action *a1 = recorder::global.at(i).at(j); - - if (a1->chan != pParent->chan->index) - continue; - - if (a1->type == ACTION_MIDI) { - - /* if this action is == to previous one: skip it, we have already - * checked it */ - - if (a1 == prev) { - //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was previous\n"); - continue; - } - - /* extract MIDI infos from a1: if is note off skip it, we are looking - * for note on only */ - - int a1_type = kernelMidi::getB1(a1->iValue); - int a1_note = kernelMidi::getB2(a1->iValue); - int a1_velo = kernelMidi::getB3(a1->iValue); - - if (a1_type == 0x80) { - //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was note off\n"); - continue; - } - - /* search for the next action. Must have: same channel, ACTION_MIDI, greater - * than a1->frame and with MIDI properties of note_off (0x80), same note - * of a1, same velocity of a1 */ - - recorder::getNextAction( - a1->chan, - ACTION_MIDI, - a1->frame, - &a2, - kernelMidi::getIValue(0x80, a1_note, a1_velo)); - - /* next action note off found: add a new gPianoItem to piano roll */ - - if (a2) { - //gLog("[gPianoRoll] ACTION_MIDI pair found, frame_a=%d frame_b=%d, note_a=%d, note_b=%d, type_a=%d, type_b=%d\n", - // a1->frame, a2->frame, kernelMidi::getNoteValue(a1->iValue), kernelMidi::getNoteValue(a2->iValue), - // kernelMidi::getNoteOnOff(a1->iValue), kernelMidi::getNoteOnOff(a2->iValue)); - new gPianoItem(0, 0, x(), y()+3, a1, a2, pParent); - prev = a2; - a2 = NULL; - } - else - gLog("[gPianoRoll] recorder didn't find action!\n"); - - } - } - } - - end(); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRoll::drawSurface1() { - - surface1 = fl_create_offscreen(40, h()); - fl_begin_offscreen(surface1); - - /* warning: only w() and h() come from this widget, x and y coordinates - * are absolute, since we are writing in a memory chunk */ - - fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN); - - fl_line_style(FL_DASH, 0, NULL); - fl_font(FL_HELVETICA, 11); - - int octave = 9; - - for (int i=1; i<=MAX_NOTES+1; i++) { - - /* print key note label. C C# D D# E F F# G G# A A# B */ - - char note[6]; - int step = i % 12; - - switch (step) { - case 1: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - sprintf(note, "%dG", octave); - break; - case 2: - sprintf(note, "%dF#", octave); - break; - case 3: - sprintf(note, "%dF", octave); - break; - case 4: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - sprintf(note, "%dE", octave); - break; - case 5: - sprintf(note, "%dD#", octave); - break; - case 6: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - sprintf(note, "%dD", octave); - break; - case 7: - sprintf(note, "%dC#", octave); - break; - case 8: - sprintf(note, "%dC", octave); - break; - case 9: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - sprintf(note, "%dB", octave); - break; - case 10: - sprintf(note, "%dA#", octave); - break; - case 11: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - sprintf(note, "%dA", octave); - break; - case 0: - sprintf(note, "%dG#", octave); - octave--; - break; - } - - fl_color(fl_rgb_color(54, 54, 54)); - fl_draw(note, 4, ((i-1)*CELL_H)+1, 30, CELL_H, (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); - - /* print horizontal line */ - - if (i < 128) - fl_line(0, i*CELL_H, 40, +i*CELL_H); - } - - fl_line_style(0); - fl_end_offscreen(); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRoll::drawSurface2() { - surface2 = fl_create_offscreen(40, h()); - fl_begin_offscreen(surface2); - fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN); - fl_color(fl_rgb_color(54, 54, 54)); - fl_line_style(FL_DASH, 0, NULL); - for (int i=1; i<=MAX_NOTES+1; i++) { - int step = i % 12; - switch (step) { - case 1: - case 4: - case 6: - case 9: - case 11: - fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); - break; - } - if (i < 128) { - fl_color(fl_rgb_color(54, 54, 54)); - fl_line(0, i*CELL_H, 40, +i*CELL_H); - } - } - fl_line_style(0); - fl_end_offscreen(); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRoll::draw() { - - fl_copy_offscreen(x(), y(), 40, h(), surface1, 0, 0); - -#if defined(__APPLE__) - for (int i=36; itotalWidth; i+=36) /// TODO: i < pParent->coverX is faster - fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 1, 0); -#else - for (int i=40; itotalWidth; i+=40) /// TODO: i < pParent->coverX is faster - fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 0, 0); -#endif - - baseDraw(false); - draw_children(); -} - - -/* ------------------------------------------------------------------ */ - - -int gPianoRoll::handle(int e) { - - int ret = Fl_Group::handle(e); - - switch (e) { - case FL_PUSH: { - - /* avoid click on grey area */ - - if (Fl::event_x() >= pParent->coverX) { - ret = 1; - break; - } - - - push_y = Fl::event_y() - y(); - - if (Fl::event_button1()) { - - /* ax is driven by grid, ay by the height in px of each note */ - - int ax = Fl::event_x(); - int ay = Fl::event_y(); - - /* vertical snap */ - - int edge = (ay-y()-3) % 15; - if (edge != 0) ay -= edge; - - /* if no overlap, add new piano item. Also check that it doesn't - * overflow on the grey area, by shifting it to the left if - * necessary. */ - - if (!onItem(ax, ay-y()-3)) { - int greyover = ax+20 - pParent->coverX-x(); - if (greyover > 0) - ax -= greyover; - add(new gPianoItem(ax, ay, ax-x(), ay-y()-3, NULL, NULL, pParent)); - redraw(); - } - } - ret = 1; - break; - } - case FL_DRAG: { - - if (Fl::event_button3()) { - - gPianoRollContainer *prc = (gPianoRollContainer*) parent(); - position(x(), Fl::event_y() - push_y); - - if (y() > prc->y()) - position(x(), prc->y()); - else - if (y() < prc->y()+prc->h()-h()) - position(x(), prc->y()+prc->h()-h()); - - prc->redraw(); - } - ret = 1; - break; - } - case FL_MOUSEWHEEL: { // nothing to do, just avoid small internal scroll - ret = 1; - break; - } - } - return ret; -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoRoll::updateActions() { - - /* when zooming, don't delete and re-add actions, just MOVE them. This - * function shifts the action by a zoom factor. Those singlepress are - * stretched, as well */ - - gPianoItem *i; - for (int k=0; kgetFrame_a(), i->getFrame_b(), i->x()); - - int newX = x() + (i->getFrame_a() / pParent->zoom); - int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom); - if (newW < 8) - newW = 8; - i->resize(newX, i->y(), newW, i->h()); - i->redraw(); - - //gLog("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x()); - } -} - - -/* ------------------------------------------------------------------ */ - - -bool gPianoRoll::onItem(int rel_x, int rel_y) { - - if (!pParent->chan->hasActions) - return false; - - int note = MAX_NOTES - (rel_y / CELL_H); - - int n = children(); - for (int i=0; igetNote() != note) - continue; - - /* when 2 segments overlap? - * start = the highest value between the two starting points - * end = the lowest value between the two ending points - * if start < end then there's an overlap of end-start pixels. We - * also add 1 px to the edges in order to gain some space: - * [ ][ ] ---> no - * [ ] [ ] ---> yes! */ - - int start = p->x() > rel_x ? p->x() : rel_x-1; - int end = p->x()+p->w() < rel_x + 20 ? p->x()+p->w() : rel_x + 21; - if (start < end) - return true; - } - return false; -} - -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ -/* ------------------------------------------------------------------ */ - - -gPianoItem::gPianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *_a, recorder::action *_b, gdActionEditor *pParent) - : Fl_Box (X, Y, 20, gPianoRoll::CELL_H-5), - a (_a), - b (_b), - pParent (pParent), - selected(false), - event_a (0x00), - event_b (0x00), - changed (false) -{ - - /* a is a pointer: action exists, needs to be displayed */ - - if (a) { - note = kernelMidi::getB2(a->iValue); - frame_a = a->frame; - frame_b = b->frame; - event_a = a->iValue; - event_b = b->iValue; - int newX = rel_x + (frame_a / pParent->zoom); - int newY = rel_y + getY(note); - int newW = (frame_b - frame_a) / pParent->zoom; - resize(newX, newY, newW, h()); - } - - /* a is null: action needs to be recorded from scratch */ - - else { - note = getNote(rel_y); - frame_a = rel_x * pParent->zoom; - frame_b = (rel_x + 20) * pParent->zoom; - record(); - size((frame_b - frame_a) / pParent->zoom, h()); - } -} - - -/* ------------------------------------------------------------------ */ - - -bool gPianoItem::overlap() { - - /* when 2 segments overlap? - * start = the highest value between the two starting points - * end = the lowest value between the two ending points - * if start < end then there's an overlap of end-start pixels. */ - - gPianoRoll *pPiano = (gPianoRoll*) parent(); - - for (int i=0; ichildren(); i++) { - - gPianoItem *pItem = (gPianoItem*) pPiano->child(i); - - /* don't check against itself and with different y positions */ - - if (pItem == this || pItem->y() != y()) - continue; - - int start = pItem->x() >= x() ? pItem->x() : x(); - int end = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w(); - if (start < end) - return true; - } - - return false; -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoItem::draw() { - int _w = w() > 4 ? w() : 4; - //gLog("[gPianoItem] draw me (%p) at x=%d\n", (void*)this, x()); - fl_rectf(x(), y(), _w, h(), (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoItem::record() { - - /* avoid frame overflow */ - - int overflow = frame_b - G_Mixer.totalFrames; - if (overflow > 0) { - frame_b -= overflow; - frame_a -= overflow; - } - - /* note off */ - /** FIXME - use constants */ - event_a |= (0x90 << 24); // note on - event_a |= (note << 16); // note value - event_a |= (0x3F << 8); // velocity - event_a |= (0x00); - - event_b |= (0x80 << 24); // note off - event_b |= (note << 16); // note value - event_b |= (0x3F << 8); // velocity - event_b |= (0x00); - - recorder::rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a); - recorder::rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b); -} - - -/* ------------------------------------------------------------------ */ - - -void gPianoItem::remove() { - recorder::deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0); - recorder::deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0); - - /* send a note-off in case we are deleting it in a middle of a key_on - * key_off sequence. */ - - ((MidiChannel*) pParent->chan)->sendMidi(event_b); -} - - -/* ------------------------------------------------------------------ */ - - -int gPianoItem::handle(int e) { - - int ret = 0; - - switch (e) { - - case FL_ENTER: { - selected = true; - ret = 1; - redraw(); - break; - } - - case FL_LEAVE: { - fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); - selected = false; - ret = 1; - redraw(); - break; - } - - case FL_MOVE: { - onLeftEdge = false; - onRightEdge = false; - - if (Fl::event_x() >= x() && Fl::event_x() < x()+4) { - onLeftEdge = true; - fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); - } - else - if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) { - onRightEdge = true; - fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); - } - else - fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); - - ret = 1; - break; - } - - case FL_PUSH: { - - push_x = Fl::event_x() - x(); - old_x = x(); - old_w = w(); - - if (Fl::event_button3()) { - fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); - remove(); - hide(); // for Windows - Fl::delete_widget(this); - ((gPianoRoll*)parent())->redraw(); - } - ret = 1; - break; - } - - case FL_DRAG: { - - changed = true; - - gPianoRoll *pr = (gPianoRoll*) parent(); - int coverX = pParent->coverX + pr->x(); // relative coverX - int nx, ny, nw; - - if (onLeftEdge) { - nx = Fl::event_x(); - ny = y(); - nw = x()-Fl::event_x()+w(); - if (nx < pr->x()) { - nx = pr->x(); - nw = w()+x()-pr->x(); - } - else - if (nx > x()+w()-8) { - nx = x()+w()-8; - nw = 8; - } - resize(nx, ny, nw, h()); - } - else - if (onRightEdge) { - nw = Fl::event_x()-x(); - if (Fl::event_x() < x()+8) - nw = 8; - else - if (Fl::event_x() > coverX) - nw = coverX-x(); - size(nw, h()); - } - else { - nx = Fl::event_x() - push_x; - if (nx < pr->x()+1) - nx = pr->x()+1; - else - if (nx+w() > coverX) - nx = coverX-w(); - - /* snapping */ - - if (pParent->gridTool->isOn()) - nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1; - - position(nx, y()); - } - - /* update screen */ - - redraw(); - ((gPianoRoll*)parent())->redraw(); - ret = 1; - break; - } - - case FL_RELEASE: { - - /* delete & record the action, only if it doesn't overlap with - * another one */ - - if (overlap()) { - resize(old_x, y(), old_w, h()); - redraw(); - } - else - if (changed) { - remove(); - note = getNote(getRelY()); - frame_a = getRelX() * pParent->zoom; - frame_b = (getRelX()+w()) * pParent->zoom; - record(); - changed = false; - } - - ((gPianoRoll*)parent())->redraw(); - - ret = 1; - break; - } - } - return ret; -} diff --git a/src/gui/elems/ge_status.cpp b/src/gui/elems/ge_status.cpp index 8acaf0f..80cbac7 100644 --- a/src/gui/elems/ge_status.cpp +++ b/src/gui/elems/ge_status.cpp @@ -28,10 +28,12 @@ #include "../../core/mixer.h" +#include "../../core/const.h" #include "ge_status.h" -extern Mixer G_Mixer; +extern Mixer G_Mixer; +extern Recorder G_Recorder; gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L) @@ -59,10 +61,10 @@ void gStatus::draw() fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // status empty - if (G_Mixer.chanInput == ch) + if (G_Mixer.recording && ch->armed) fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3); // take in progress else - if (recorder::active && recorder::canRec(ch)) + if (G_Recorder.active && G_Recorder.canRec(ch)) fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4); // action record /* equation for the progress bar: diff --git a/src/gui/elems/ge_waveTools.cpp b/src/gui/elems/ge_waveTools.cpp index 49f9735..7e7b197 100644 --- a/src/gui/elems/ge_waveTools.cpp +++ b/src/gui/elems/ge_waveTools.cpp @@ -29,6 +29,7 @@ #include "../../core/graphics.h" #include "../../core/mixer.h" +#include "../../core/const.h" #include "../elems/ge_mixed.h" #include "../elems/ge_waveform.h" #include "ge_waveTools.h" @@ -54,7 +55,7 @@ gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char /* ------------------------------------------------------------------ */ -void gWaveTools::updateWaveform() +void gWaveTools::updateWaveform() { waveform->alloc(w()); waveform->redraw(); @@ -64,7 +65,7 @@ void gWaveTools::updateWaveform() /* ------------------------------------------------------------------ */ -void gWaveTools::resize(int x, int y, int w, int h) +void gWaveTools::resize(int x, int y, int w, int h) { if (this->w() == w || (this->w() != w && this->h() != h)) { // vertical or both resize Fl_Widget::resize(x, y, w, h); @@ -87,7 +88,7 @@ void gWaveTools::resize(int x, int y, int w, int h) /* ------------------------------------------------------------------ */ -int gWaveTools::handle(int e) +int gWaveTools::handle(int e) { int ret = Fl_Group::handle(e); switch (e) { @@ -100,4 +101,3 @@ int gWaveTools::handle(int e) } return ret; } - diff --git a/src/gui/elems/ge_waveform.cpp b/src/gui/elems/ge_waveform.cpp index 5d8a48f..dd893ce 100644 --- a/src/gui/elems/ge_waveform.cpp +++ b/src/gui/elems/ge_waveform.cpp @@ -33,11 +33,12 @@ #include #include "../../core/wave.h" #include "../../core/conf.h" +#include "../../core/const.h" #include "../../core/mixer.h" #include "../../core/waveFx.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" -#include "../../glue/glue.h" +#include "../../glue/channel.h" #include "../dialogs/gd_editor.h" #include "ge_waveTools.h" #include "ge_mixed.h" @@ -250,7 +251,7 @@ void gWaveform::draw() for (unsigned k=0; k #include #include -#include "../../utils/utils.h" +#include "../../utils/fs.h" using std::vector; diff --git a/src/gui/elems/ge_window.cpp b/src/gui/elems/ge_window.cpp index 30c26cb..e14fcb8 100644 --- a/src/gui/elems/ge_window.cpp +++ b/src/gui/elems/ge_window.cpp @@ -75,7 +75,7 @@ void gWindow::addSubWindow(gWindow *w) { /** TODO - useless: delete ---------------------------------------- */ for (unsigned i=0; igetId() == subWindows.at(i)->getId()) { - //gLog("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId()); + //gu_log("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId()); delete w; return; } @@ -138,10 +138,10 @@ void gWindow::setId(int id) { void gWindow::debug() { - gLog("---- window stack (id=%d): ----\n", getId()); + gu_log("---- window stack (id=%d): ----\n", getId()); for (unsigned i=0; igetId()); - gLog("----\n"); + gu_log("[gWindow] %p (id=%d)\n", (void*)subWindows.at(i), subWindows.at(i)->getId()); + gu_log("----\n"); } diff --git a/src/gui/elems/ge_window.h b/src/gui/elems/ge_window.h index 4991b0f..e986d8d 100644 --- a/src/gui/elems/ge_window.h +++ b/src/gui/elems/ge_window.h @@ -34,7 +34,7 @@ #include #include -#include "../../utils/utils.h" +#include "../../utils/fs.h" using std::vector; diff --git a/src/gui/elems/ge_midiChannel.cpp b/src/gui/elems/midiChannel.cpp similarity index 64% rename from src/gui/elems/ge_midiChannel.cpp rename to src/gui/elems/midiChannel.cpp index bd139c3..bfdbea5 100644 --- a/src/gui/elems/ge_midiChannel.cpp +++ b/src/gui/elems/midiChannel.cpp @@ -27,18 +27,16 @@ * -------------------------------------------------------------------------- */ -#include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" -#include "../../core/wave.h" -#include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../glue/channel.h" -#include "../../glue/glue.h" -#include "../../utils/gui_utils.h" +#include "../../glue/main.h" +#include "../../glue/io.h" +#include "../../utils/gui.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiInput.h" @@ -48,32 +46,31 @@ #include "../dialogs/gd_browser.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiOutput.h" -#include "ge_keyboard.h" -#include "ge_midiChannel.h" -#include "ge_channel.h" -#include "ge_sampleChannel.h" #include "../dialogs/gd_pluginList.h" +#include "midiChannel.h" extern Mixer G_Mixer; extern Conf G_Conf; +extern Recorder G_Recorder; extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; -gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch) - : gChannel(X, Y, W, H, CHANNEL_MIDI), ch(ch) +geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch) + : geChannel(X, Y, W, H, CHANNEL_MIDI, ch) { begin(); #if defined(WITH_VST) - int delta = 120; // (5 widgets * 20) + (5 paddings * 4) + int delta = 144; // (6 widgets * 20) + (6 paddings * 4) #else - int delta = 96; // (4 widgets * 20) + (4 paddings * 4) + int delta = 120; // (5 widgets * 20) + (5 paddings * 4) #endif button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); - mainButton = new gMidiChannelButton(button->x()+button->w()+4, y(), w() - delta, 20, "-- MIDI --"); + arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); + mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --"); mute = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); #if defined(WITH_VST) @@ -92,6 +89,9 @@ gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch) button->callback(cb_button, (void*)this); button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease + arm->type(FL_TOGGLE_BUTTON); + arm->callback(cb_arm, (void*)this); + #ifdef WITH_VST fx->callback(cb_openFxWindow, (void*)this); #endif @@ -113,57 +113,14 @@ gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch) /* -------------------------------------------------------------------------- */ -void gMidiChannel::cb_button (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_button(); } -void gMidiChannel::cb_mute (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_mute(); } -void gMidiChannel::cb_solo (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_solo(); } -void gMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openMenu(); } -void gMidiChannel::cb_changeVol (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_changeVol(); } -#ifdef WITH_VST -void gMidiChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openFxWindow(); } -#endif - - -/* -------------------------------------------------------------------------- */ - - -void gMidiChannel::__cb_mute() -{ - glue_setMute(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void gMidiChannel::__cb_solo() -{ - solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void gMidiChannel::__cb_changeVol() -{ - glue_setChanVol(ch, vol->value()); -} +void geMidiChannel::cb_button (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_button(); } +void geMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_openMenu(); } /* -------------------------------------------------------------------------- */ -#ifdef WITH_VST -void gMidiChannel::__cb_openFxWindow() -{ - gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); -} -#endif - -/* -------------------------------------------------------------------------- */ - - -void gMidiChannel::__cb_button() +void geMidiChannel::__cb_button() { if (button->value()) glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); @@ -173,7 +130,7 @@ void gMidiChannel::__cb_button() /* -------------------------------------------------------------------------- */ -void gMidiChannel::__cb_openMenu() +void geMidiChannel::__cb_openMenu() { Fl_Menu_Item rclick_menu[] = { {"Edit actions..."}, // 0 @@ -215,7 +172,7 @@ void gMidiChannel::__cb_openMenu() } if (strcmp(m->label(), "Setup keyboard input...") == 0) { - gu_openSubWindow(mainWin, new gdKeyGrabber(ch), 0); + gu_openSubWindow(G_MainWin, new gdKeyGrabber(ch), 0); //new gdKeyGrabber(ch); return; } @@ -223,24 +180,24 @@ void gMidiChannel::__cb_openMenu() if (strcmp(m->label(), "All") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; - recorder::clearChan(ch->index); + G_Recorder.clearChan(ch->index); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Edit actions...") == 0) { - gu_openSubWindow(mainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); + gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); return; } if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); + gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); return; } if (strcmp(m->label(), "Setup MIDI output...") == 0) { - //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); - gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0); + //gu_openSubWindow(G_MainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); + gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh((MidiChannel*) ch), 0); return; } } @@ -249,7 +206,7 @@ void gMidiChannel::__cb_openMenu() /* -------------------------------------------------------------------------- */ -void gMidiChannel::refresh() +void geMidiChannel::refresh() { setColorsByStatus(ch->status, ch->recStatus); mainButton->redraw(); @@ -259,7 +216,7 @@ void gMidiChannel::refresh() /* -------------------------------------------------------------------------- */ -void gMidiChannel::reset() +void geMidiChannel::reset() { mainButton->setDefaultMode("-- MIDI --"); mainButton->redraw(); @@ -269,11 +226,11 @@ void gMidiChannel::reset() /* -------------------------------------------------------------------------- */ -void gMidiChannel::update() +void geMidiChannel::update() { - if (ch->midiOut) { + if (((MidiChannel*) ch)->midiOut) { char tmp[32]; - sprintf(tmp, "-- MIDI (channel %d) --", ch->midiOutChan+1); + sprintf(tmp, "-- MIDI (channel %d) --", ((MidiChannel*) ch)->midiOutChan+1); mainButton->copy_label(tmp); } else @@ -295,37 +252,23 @@ void gMidiChannel::update() /* -------------------------------------------------------------------------- */ -void gMidiChannel::resize(int X, int Y, int W, int H) +void geMidiChannel::resize(int X, int Y, int W, int H) { - gChannel::resize(X, Y, W, H); - - /* this stuff makes sense only with FX button available. Do nothing - * otherwise */ + geChannel::resize(X, Y, W, H); + arm->hide(); #ifdef WITH_VST - if (w() < BREAK_FX) { - fx->hide(); + fx->hide(); +#endif - mainButton->size(w() - (BREAK_DELTA - BREAK_UNIT), mainButton->h()); - } - else { + if (w() > BREAK_ARM) + arm->show(); +#ifdef WITH_VST + if (w() > BREAK_FX) fx->show(); - mainButton->size(w() - BREAK_DELTA, mainButton->h()); - } - mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - solo->resize(mute->x()+mute->w()+4, y(), 20, 20); - - gChannel::init_sizes(); #endif -} - -/* -------------------------------------------------------------------------- */ - - -int gMidiChannel::keyPress(int e) -{ - return handleKey(e, ch->key); + packWidgets(); } @@ -334,14 +277,14 @@ int gMidiChannel::keyPress(int e) /* -------------------------------------------------------------------------- */ -gMidiChannelButton::gMidiChannelButton(int x, int y, int w, int h, const char *l) - : gChannelButton(x, y, w, h, l) {} +geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char *l) + : geChannelButton(x, y, w, h, l) {} /* -------------------------------------------------------------------------- */ -int gMidiChannelButton::handle(int e) +int geMidiChannelButton::handle(int e) { // MIDI drag-n-drop does nothing so far. return gClick::handle(e); diff --git a/src/gui/elems/ge_midiChannel.h b/src/gui/elems/midiChannel.h similarity index 66% rename from src/gui/elems/ge_midiChannel.h rename to src/gui/elems/midiChannel.h index ac1141a..cd06ddc 100644 --- a/src/gui/elems/ge_midiChannel.h +++ b/src/gui/elems/midiChannel.h @@ -31,58 +31,40 @@ #define GE_MIDI_CHANNEL_H -#include -#include -#include -#include "ge_channel.h" -#include "ge_channelButton.h" -#include "ge_mixed.h" +#include "channel.h" +#include "channelButton.h" -class gMidiChannel : public gChannel +class geMidiChannel : public geChannel { private: static void cb_button (Fl_Widget *v, void *p); - static void cb_mute (Fl_Widget *v, void *p); - static void cb_solo (Fl_Widget *v, void *p); static void cb_openMenu (Fl_Widget *v, void *p); - static void cb_changeVol (Fl_Widget *v, void *p); -#ifdef WITH_VST - static void cb_openFxWindow (Fl_Widget *v, void *p); -#endif - inline void __cb_mute (); - inline void __cb_solo (); - inline void __cb_changeVol (); inline void __cb_button (); inline void __cb_openMenu (); inline void __cb_readActions (); -#ifdef WITH_VST - inline void __cb_openFxWindow(); -#endif public: - gMidiChannel(int x, int y, int w, int h, class MidiChannel *ch); + geMidiChannel(int x, int y, int w, int h, class MidiChannel *ch); void reset (); void update (); void refresh (); - int keyPress(int event); + int keyPress(int event); // TODO - move to base class void resize (int x, int y, int w, int h); - - class MidiChannel *ch; }; /* -------------------------------------------------------------------------- */ -class gMidiChannelButton : public gChannelButton +class geMidiChannelButton : public geChannelButton { public: - gMidiChannelButton(int x, int y, int w, int h, const char *l=0); + geMidiChannelButton(int x, int y, int w, int h, const char *l=0); int handle(int e); }; diff --git a/src/gui/elems/ge_muteChannel.cpp b/src/gui/elems/muteEditor.cpp similarity index 79% rename from src/gui/elems/ge_muteChannel.cpp rename to src/gui/elems/muteEditor.cpp index 7b996b8..e2861b2 100644 --- a/src/gui/elems/ge_muteChannel.cpp +++ b/src/gui/elems/muteEditor.cpp @@ -1,11 +1,8 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * - * ge_muteChannel - * a widget that represents mute actions inside the action editor. - * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -25,27 +22,29 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include "../../core/recorder.h" #include "../../core/mixer.h" #include "../../core/channel.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" #include "../../utils/log.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" #include "ge_keyboard.h" -#include "ge_actionWidget.h" -#include "ge_muteChannel.h" +#include "muteEditor.h" -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; extern Mixer G_Mixer; +extern Recorder G_Recorder; -gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent) - : gActionWidget(x, y, 200, 80, pParent), draggedPoint(-1), selectedPoint(-1) +geMuteEditor::geMuteEditor(int x, int y, gdActionEditor *pParent) + : geBaseActionEditor(x, y, 200, 80, pParent), + draggedPoint (-1), + selectedPoint (-1) { size(pParent->totalWidth, h()); extractPoints(); @@ -55,8 +54,8 @@ gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent) /* ------------------------------------------------------------------ */ -void gMuteChannel::draw() { - +void geMuteEditor::draw() +{ baseDraw(); /* print label */ @@ -120,22 +119,22 @@ void gMuteChannel::draw() { /* ------------------------------------------------------------------ */ -void gMuteChannel::extractPoints() { - +void geMuteEditor::extractPoints() +{ points.clear(); - /* actions are already sorted by recorder::sortActions() */ + /* actions are already sorted by G_Recorder.sortActions() */ - for (unsigned i=0; ichan == pParent->chan->index) { - if (recorder::global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) { + for (unsigned i=0; ichan == pParent->chan->index) { + if (G_Recorder.global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) { point p; - p.frame = recorder::frames.at(i); - p.type = recorder::global.at(i).at(j)->type; + p.frame = G_Recorder.frames.at(i); + p.type = G_Recorder.global.at(i).at(j)->type; p.x = p.frame / pParent->zoom; points.push_back(p); - //gLog("[gMuteChannel::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame); + //gu_log("[geMuteEditor::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame); } } } @@ -146,7 +145,7 @@ void gMuteChannel::extractPoints() { /* ------------------------------------------------------------------ */ -void gMuteChannel::updateActions() { +void geMuteEditor::updateActions() { for (unsigned i=0; izoom; } @@ -155,7 +154,7 @@ void gMuteChannel::updateActions() { /* ------------------------------------------------------------------ */ -int gMuteChannel::handle(int e) { +int geMuteEditor::handle(int e) { int ret = 0; int mouseX = Fl::event_x()-x(); @@ -247,16 +246,16 @@ int gMuteChannel::handle(int e) { } if (nextPoint % 2 != 0) { - recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_a); - recorder::rec(pParent->chan->index, ACTION_MUTEON, frame_b); + G_Recorder.rec(pParent->chan->index, ACTION_MUTEOFF, frame_a); + G_Recorder.rec(pParent->chan->index, ACTION_MUTEON, frame_b); } else { - recorder::rec(pParent->chan->index, ACTION_MUTEON, frame_a); - recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_b); + G_Recorder.rec(pParent->chan->index, ACTION_MUTEON, frame_a); + G_Recorder.rec(pParent->chan->index, ACTION_MUTEOFF, frame_b); } - recorder::sortActions(); + G_Recorder.sortActions(); - mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow extractPoints(); redraw(); } @@ -279,14 +278,14 @@ int gMuteChannel::handle(int e) { b = selectedPoint+1; } - //gLog("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n", + //gu_log("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n", // a, b, points.at(a).frame, points.at(b).frame); - recorder::deleteAction(pParent->chan->index, points.at(a).frame, points.at(a).type, false); // false = don't check vals - recorder::deleteAction(pParent->chan->index, points.at(b).frame, points.at(b).type, false); // false = don't check vals - recorder::sortActions(); + G_Recorder.deleteAction(pParent->chan->index, points.at(a).frame, points.at(a).type, false); // false = don't check vals + G_Recorder.deleteAction(pParent->chan->index, points.at(b).frame, points.at(b).type, false); // false = don't check vals + G_Recorder.sortActions(); - mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow + G_MainWin->keyboard->setChannelWithActions((geSampleChannel*)pParent->chan->guiChannel); // update mainWindow extractPoints(); redraw(); } @@ -300,24 +299,24 @@ int gMuteChannel::handle(int e) { if (draggedPoint != -1) { if (points.at(draggedPoint).x == previousXPoint) { - //gLog("nothing to do\n"); + //gu_log("nothing to do\n"); } else { int newFrame = points.at(draggedPoint).x * pParent->zoom; - recorder::deleteAction( + G_Recorder.deleteAction( pParent->chan->index, points.at(draggedPoint).frame, points.at(draggedPoint).type, false); // don't check values - recorder::rec( + G_Recorder.rec( pParent->chan->index, points.at(draggedPoint).type, newFrame); - recorder::sortActions(); + G_Recorder.sortActions(); points.at(draggedPoint).frame = newFrame; } @@ -387,7 +386,7 @@ int gMuteChannel::handle(int e) { /* ------------------------------------------------------------------ */ -bool gMuteChannel::pointCollides(int frame) { +bool geMuteEditor::pointCollides(int frame) { for (unsigned i=0; i. * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef GE_MUTECHANNEL_H @@ -36,21 +33,22 @@ #include #include #include -#include "../../utils/utils.h" -#include "ge_actionWidget.h" +#include "../../utils/fs.h" +#include "baseActionEditor.h" using std::vector; -class gMuteChannel : public gActionWidget +class geMuteEditor : public geBaseActionEditor { private: /* point * a single dot in the graph. */ - struct point { + struct point + { int frame; char type; int x; @@ -94,7 +92,7 @@ private: public: - gMuteChannel(int x, int y, class gdActionEditor *pParent); + geMuteEditor(int x, int y, class gdActionEditor *pParent); void draw(); int handle(int e); diff --git a/src/gui/elems/noteEditor.cpp b/src/gui/elems/noteEditor.cpp new file mode 100644 index 0000000..19940a2 --- /dev/null +++ b/src/gui/elems/noteEditor.cpp @@ -0,0 +1,90 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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 "../../core/const.h" +#include "../../core/conf.h" +#include "../../utils/log.h" +#include "../dialogs/gd_actionEditor.h" +#include "pianoItem.h" +#include "pianoRoll.h" +#include "noteEditor.h" + + +extern Conf G_Conf; + + +geNoteEditor::geNoteEditor(int x, int y, gdActionEditor *pParent) + : Fl_Scroll(x, y, 200, 422), + pParent (pParent) +{ + size(pParent->totalWidth, G_Conf.pianoRollH); + pianoRoll = new gePianoRoll(x, y, pParent->totalWidth, pParent); +} + + +/* -------------------------------------------------------------------------- */ + + +geNoteEditor::~geNoteEditor() +{ + clear(); + G_Conf.pianoRollH = h(); + G_Conf.pianoRollY = pianoRoll->y(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geNoteEditor::updateActions() +{ + pianoRoll->updateActions(); +} + + +/* -------------------------------------------------------------------------- */ + + +void geNoteEditor::draw() +{ + pianoRoll->size(this->w(), pianoRoll->h()); /// <--- not optimal + + /* clear background */ + + fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN); + + /* clip pianoRoll to pianoRollContainer size */ + + fl_push_clip(x(), y(), w(), h()); + draw_child(*pianoRoll); + fl_pop_clip(); + + fl_color(COLOR_BD_0); + fl_line_style(0); + fl_rect(x(), y(), pParent->totalWidth, h()); +} diff --git a/src/gui/elems/noteEditor.h b/src/gui/elems/noteEditor.h new file mode 100644 index 0000000..0ca600f --- /dev/null +++ b/src/gui/elems/noteEditor.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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_NOTE_EDITOR_H +#define GE_NOTE_EDITOR_H + +#include +#include +#include +#include +#include "../../core/recorder.h" + + +class geNoteEditor : public Fl_Scroll +{ +private: + + class gdActionEditor *pParent; + class gePianoRoll *pianoRoll; + +public: + + geNoteEditor(int x, int y, class gdActionEditor *parent); + ~geNoteEditor(); + void draw(); + void updateActions(); +}; + + +#endif diff --git a/src/gui/elems/pianoItem.cpp b/src/gui/elems/pianoItem.cpp new file mode 100644 index 0000000..870b61a --- /dev/null +++ b/src/gui/elems/pianoItem.cpp @@ -0,0 +1,348 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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 "../../core/kernelMidi.h" +#include "../../core/mixer.h" +#include "../../core/channel.h" +#include "../../core/midiChannel.h" +#include "../dialogs/gd_actionEditor.h" +#include "noteEditor.h" +#include "pianoRoll.h" +#include "pianoItem.h" + + +extern KernelMidi G_KernelMidi; +extern Mixer G_Mixer; +extern Recorder G_Recorder; + + +gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, Recorder::action *_a, + Recorder::action *_b, gdActionEditor *pParent) + : Fl_Box (X, Y, MIN_WIDTH, gePianoRoll::CELL_H), + a (_a), + b (_b), + pParent (pParent), + selected(false), + event_a (0x00), + event_b (0x00), + changed (false) +{ + /* a is a pointer: action exists, needs to be displayed */ + + if (a) { + note = G_KernelMidi.getB2(a->iValue); + frame_a = a->frame; + frame_b = b->frame; + event_a = a->iValue; + event_b = b->iValue; + int newX = rel_x + (frame_a / pParent->zoom); + int newY = rel_y + getY(note); + int newW = (frame_b - frame_a) / pParent->zoom; + resize(newX, newY, newW, h()); + } + + /* a is null: action needs to be recorded from scratch */ + + else { + note = getNote(rel_y); + frame_a = rel_x * pParent->zoom; + frame_b = (rel_x + 20) * pParent->zoom; + record(); + size((frame_b - frame_a) / pParent->zoom, h()); + } +} + + +/* -------------------------------------------------------------------------- */ + + +bool gePianoItem::overlap() +{ + /* when 2 segments overlap? + * start = the highest value between the two starting points + * end = the lowest value between the two ending points + * if start < end then there's an overlap of end-start pixels. */ + + geNoteEditor *pPiano = (geNoteEditor*) parent(); + + for (int i=0; ichildren(); i++) { + + gePianoItem *pItem = (gePianoItem*) pPiano->child(i); + + /* don't check against itself and with different y positions */ + + if (pItem == this || pItem->y() != y()) + continue; + + int start = pItem->x() >= x() ? pItem->x() : x(); + int end = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w(); + if (start < end) + return true; + } + + return false; +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoItem::draw() +{ + int _w = w() > MIN_WIDTH ? w() : MIN_WIDTH; + fl_rectf(x(), y()+2, _w, h()-3, (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2); +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoItem::record() +{ + /* avoid frame overflow */ + + int overflow = frame_b - G_Mixer.totalFrames; + if (overflow > 0) { + frame_b -= overflow; + frame_a -= overflow; + } + + event_a |= (MIDI_NOTE_ON); + event_a |= (note << 16); // note value + event_a |= (MIDI_VELOCITY); + event_a |= (0x00); + + event_b |= (MIDI_NOTE_OFF); + event_b |= (note << 16); // note value + event_b |= (MIDI_VELOCITY); + event_b |= (0x00); + + G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a); + G_Recorder.rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b); +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoItem::remove() +{ + G_Recorder.deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0); + G_Recorder.deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0); + + /* send a note-off in case we are deleting it in a middle of a key_on + * key_off sequence. */ + + ((MidiChannel*) pParent->chan)->sendMidi(event_b); + + ((gePianoRoll*) parent())->cursorOnItem = false; +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoItem::handle(int e) +{ + int ret = 0; + + switch (e) { + + case FL_ENTER: { + ((gePianoRoll*) parent())->cursorOnItem = true; + selected = true; + ret = 1; + redraw(); + break; + } + + case FL_LEAVE: { + fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); + ((gePianoRoll*) parent())->cursorOnItem = false; + selected = false; + ret = 1; + redraw(); + break; + } + + case FL_MOVE: { + onLeftEdge = false; + onRightEdge = false; + + if (Fl::event_x() >= x() && Fl::event_x() < x()+HANDLE_WIDTH) { + onLeftEdge = true; + fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); + } + else + if (Fl::event_x() >= x()+w()-HANDLE_WIDTH && Fl::event_x() <= x()+w()) { + onRightEdge = true; + fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); + } + else + fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); + + ret = 1; + break; + } + + case FL_PUSH: { + + push_x = Fl::event_x() - x(); + old_x = x(); + old_w = w(); + + if (Fl::event_button3()) { + fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); + remove(); + hide(); // for Windows + Fl::delete_widget(this); + ((geNoteEditor*)parent())->redraw(); + } + ret = 1; + break; + } + + case FL_DRAG: { + + changed = true; + + geNoteEditor *pr = (geNoteEditor*) parent(); + int coverX = pParent->coverX + pr->x(); // relative coverX + int nx, ny, nw; + + if (onLeftEdge) { + nx = Fl::event_x(); + ny = y(); + nw = x()-Fl::event_x()+w(); + if (nx < pr->x()) { + nx = pr->x(); + nw = w()+x()-pr->x(); + } + else + if (nx > x()+w()-MIN_WIDTH) { + nx = x()+w()-MIN_WIDTH; + nw = MIN_WIDTH; + } + resize(nx, ny, nw, h()); + } + else + if (onRightEdge) { + nw = Fl::event_x()-x(); + if (Fl::event_x() < x()+MIN_WIDTH) + nw = MIN_WIDTH; + else + if (Fl::event_x() > coverX) + nw = coverX-x(); + size(nw, h()); + } + else { + nx = Fl::event_x() - push_x; + if (nx < pr->x()+1) + nx = pr->x()+1; + else + if (nx+w() > coverX) + nx = coverX-w(); + + /* snapping */ + + if (pParent->gridTool->isOn()) + nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1; + + position(nx, y()); + } + + /* update screen */ + + redraw(); + ((geNoteEditor*)parent())->redraw(); + ret = 1; + break; + } + + case FL_RELEASE: { + + /* delete & record the action, only if it doesn't overlap with + * another one */ + + if (overlap()) { + resize(old_x, y(), old_w, h()); + redraw(); + } + else + if (changed) { + remove(); + note = getNote(getRelY()); + frame_a = getRelX() * pParent->zoom; + frame_b = (getRelX()+w()) * pParent->zoom; + record(); + changed = false; + } + + ((geNoteEditor*)parent())->redraw(); + + ret = 1; + break; + } + } + return ret; +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoItem::getNote(int rel_y) +{ + return gePianoRoll::MAX_KEYS - (rel_y / gePianoRoll::CELL_H); +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoItem::getRelY() +{ + return y() - parent()->y(); +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoItem::getRelX() +{ + return x() - parent()->x(); +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoItem::getY(int note) +{ + return (gePianoRoll::MAX_KEYS * gePianoRoll::CELL_H) - (note * gePianoRoll::CELL_H); +} diff --git a/src/gui/elems/ge_pianoRoll.h b/src/gui/elems/pianoItem.h similarity index 54% rename from src/gui/elems/ge_pianoRoll.h rename to src/gui/elems/pianoItem.h index 509fd32..0aa4b2b 100644 --- a/src/gui/elems/ge_pianoRoll.h +++ b/src/gui/elems/pianoItem.h @@ -1,10 +1,8 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * - * ge_pianoRoll - * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,112 +22,46 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ + +#ifndef GE_PIANO_ITEM_H +#define GE_PIANO_ITEM_H -#ifndef GE_PIANOROLL_H -#define GE_PIANOROLL_H -#include -#include #include #include "../../core/recorder.h" -#include "ge_actionWidget.h" - - -class gPianoRollContainer : public Fl_Scroll { - -private: - class gdActionEditor *pParent; - class gPianoRoll *pianoRoll; - -public: - gPianoRollContainer(int x, int y, class gdActionEditor *parent); - ~gPianoRollContainer(); - void draw(); - void updateActions(); -}; - - -/* ------------------------------------------------------------------ */ -class gPianoRoll : public gActionWidget { - -private: - - /* onItem - * is curson on a gPianoItem? */ - - bool onItem(int rel_x, int rel_y); - - /* drawSurface* - * generate a complex drawing in memory first and copy it to the - * screen at a later point in time. Fl_Offscreen surface holds the - * necessary data. */ - - /* drawSurface1 - * draw first tile of note values. */ - - void drawSurface1(); - - /* drawSurface2 - * draw the rest of the piano roll. */ - - void drawSurface2(); - - int push_y; - Fl_Offscreen surface1; // notes, no repeat - Fl_Offscreen surface2; // lines, x-repeat - - -public: - gPianoRoll(int x, int y, int w, class gdActionEditor *pParent); - - void draw(); - int handle(int e); - void updateActions(); - - enum { MAX_NOTES = 127, CELL_H = 15 }; -}; - - -/* ------------------------------------------------------------------ */ - - -class gPianoItem : public Fl_Box { - +class gePianoItem : public Fl_Box +{ private: /* getRelX/Y * return x/y point of this item, relative to piano roll (and not to * entire screen) */ - inline int getRelY() { return y() - parent()->y() - 3; }; - inline int getRelX() { return x() - parent()->x(); }; + int getRelY(); + int getRelX(); /* getNote * from a relative_y return the real MIDI note, range 0-127. 15 is * the hardcoded value for note height in pixels */ - inline int getNote(int rel_y) { - return gPianoRoll::MAX_NOTES - (rel_y / gPianoRoll::CELL_H); - }; + int getNote(int rel_y); /* getY * from a note, return the y position on piano roll */ - inline int getY(int note) { - return (gPianoRoll::MAX_NOTES * gPianoRoll::CELL_H) - (note * gPianoRoll::CELL_H); - }; + int getY(int note); /* overlap * check if this item don't overlap with another one. */ bool overlap(); - recorder::action *a; - recorder::action *b; + struct Recorder::action *a; + struct Recorder::action *b; class gdActionEditor *pParent; bool selected; @@ -164,20 +96,24 @@ private: public: + static const int MIN_WIDTH = 10; + static const int HANDLE_WIDTH = 5; + /* pianoItem ctor * if action *a == NULL, record a new action */ - gPianoItem(int x, int y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, class gdActionEditor *pParent); + gePianoItem(int x, int y, int rel_x, int rel_y, struct Recorder::action *a, + struct Recorder::action *b, class gdActionEditor *pParent); void draw(); int handle(int e); void record(); void remove(); - inline int getFrame_a() { return frame_a; } - inline int getFrame_b() { return frame_b; } - inline int getNote() { return note; } - + int getFrame_a() { return frame_a; } + int getFrame_b() { return frame_b; } + int getNote() { return note; } }; + #endif diff --git a/src/gui/elems/pianoRoll.cpp b/src/gui/elems/pianoRoll.cpp new file mode 100644 index 0000000..b8f776b --- /dev/null +++ b/src/gui/elems/pianoRoll.cpp @@ -0,0 +1,360 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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 "../../core/conf.h" +#include "../../core/mixer.h" +#include "../../core/channel.h" +#include "../../core/recorder.h" +#include "../../core/kernelMidi.h" +#include "../../utils/log.h" +#include "../dialogs/gd_actionEditor.h" +#include "pianoItem.h" +#include "noteEditor.h" +#include "pianoRoll.h" + + +extern Conf G_Conf; +extern Recorder G_Recorder; +extern Mixer G_Mixer; +extern KernelMidi G_KernelMidi; + + +gePianoRoll::gePianoRoll(int X, int Y, int W, gdActionEditor *pParent) + : geBaseActionEditor(X, Y, W, 40, pParent), + cursorOnItem (false) +{ + resizable(nullptr); // don't resize children (i.e. pianoItem) + size(W, (MAX_KEYS+1) * CELL_H); // 128 MIDI channels * CELL_H height + + if (G_Conf.pianoRollY == -1) + position(x(), y()-(h()/2)); // center + else + position(x(), G_Conf.pianoRollY); + + drawSurface1(); + drawSurface2(); + + /* add actions when the window is opened. Position is zoom-based. MIDI + * actions come always in pair: start + end. */ + + G_Recorder.sortActions(); + + Recorder::action *a2 = nullptr; + Recorder::action *prev = nullptr; + + for (unsigned i=0; i than the grey area */ + /** FIXME - can we move this to the outer cycle? */ + + if (G_Recorder.frames.at(i) > G_Mixer.totalFrames) + continue; + + Recorder::action *a1 = G_Recorder.global.at(i).at(j); + + /* Skip action if: + - does not belong to this channel + - is not a MIDI action (we only want MIDI things here) + - is the previous one (we have already checked it) + - (later on) if it's NOTE_OFF (0x80): we want note on only */ + + if (a1->chan != pParent->chan->index) + continue; + if (a1->type != ACTION_MIDI) + continue; + if (a1 == prev) + continue; + + /* extract MIDI infos from a1: if is note off skip it, we are looking + * for note on only */ + + int a1_type = G_KernelMidi.getB1(a1->iValue); + int a1_note = G_KernelMidi.getB2(a1->iValue); + + if (a1_type == 0x80) // NOTE_OFF + continue; + + /* Search for the next action. Must have: same channel, ACTION_MIDI, + greater than a1->frame and with MIDI properties of note_off (0x80), same + note of a1, any velocity value (0xFF) because we just don't care about the + velocity of a note_off. */ + + G_Recorder.getNextAction(a1->chan, ACTION_MIDI, a1->frame, &a2, + G_KernelMidi.getIValue(0x80, a1_note, 0xFF)); + + /* next action note_off found: add a new gePianoItem to piano roll */ + + if (a2) { + new gePianoItem(0, 0, x(), y(), a1, a2, pParent); + prev = a2; + a2 = nullptr; + } + else + gu_log("[geNoteEditor] recorder didn't find requested action!\n"); + // TODO - create new gOrphanedPianoItem + } + } + + end(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoRoll::drawSurface1() +{ + surface1 = fl_create_offscreen(CELL_W, h()); + fl_begin_offscreen(surface1); + + /* warning: only w() and h() come from this widget, x and y coordinates + * are absolute, since we are writing in a memory chunk */ + + fl_rectf(0, 0, CELL_W, h(), COLOR_BG_MAIN); + + fl_line_style(FL_DASH, 0, nullptr); + fl_font(FL_HELVETICA, GUI_FONT_SIZE_BASE); + + int octave = MAX_OCTAVES; + + for (int i=1; i<=MAX_KEYS+1; i++) { + + /* print key note label. C C# D D# E F F# G G# A A# B */ + + char note[6]; + switch (i % KEYS) { + case (int) Notes::G: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + sprintf(note, "%dG", octave); + break; + case (int) Notes::FS: + sprintf(note, "%dF#", octave); + break; + case (int) Notes::F: + sprintf(note, "%dF", octave); + break; + case (int) Notes::E: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + sprintf(note, "%dE", octave); + break; + case (int) Notes::DS: + sprintf(note, "%dD#", octave); + break; + case (int) Notes::D: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + sprintf(note, "%dD", octave); + break; + case (int) Notes::CS: + sprintf(note, "%dC#", octave); + break; + case (int) Notes::C: + sprintf(note, "%dC", octave); + break; + case (int) Notes::B: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + sprintf(note, "%dB", octave); + break; + case (int) Notes::AS: + sprintf(note, "%dA#", octave); + break; + case (int) Notes::A: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + sprintf(note, "%dA", octave); + break; + case (int) Notes::GS: + sprintf(note, "%dG#", octave); + octave--; + break; + } + + /* Print note name */ + + fl_color(COLOR_BG_LINE); + fl_draw(note, 4, ((i-1)*CELL_H)+1, CELL_W, CELL_H, + (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); + + /* Print horizontal line */ + + if (i < MAX_KEYS+1) + fl_line(0, i*CELL_H, CELL_W, +i*CELL_H); + } + + fl_line_style(0); + fl_end_offscreen(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoRoll::drawSurface2() +{ + surface2 = fl_create_offscreen(CELL_W, h()); + fl_begin_offscreen(surface2); + fl_rectf(0, 0, CELL_W, h(), COLOR_BG_MAIN); + fl_color(COLOR_BG_LINE); + fl_line_style(FL_DASH, 0, nullptr); + for (int i=1; i<=MAX_KEYS+1; i++) { + switch (i % KEYS) { + case (int) Notes::G: + case (int) Notes::E: + case (int) Notes::D: + case (int) Notes::B: + case (int) Notes::A: + fl_rectf(0, i*CELL_H, CELL_W, CELL_H, COLOR_BG_RICH); + break; + } + if (i < MAX_KEYS+1) { + fl_color(COLOR_BG_LINE); + fl_line(0, i*CELL_H, CELL_W, i*CELL_H); + } + } + fl_line_style(0); + fl_end_offscreen(); +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoRoll::draw() +{ + fl_copy_offscreen(x(), y(), CELL_W, h(), surface1, 0, 0); + +#if defined(__APPLE__) + for (int i=36; itotalWidth; i+=36) /// TODO: i < pParent->coverX is faster + fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 1, 0); +#else + for (int i=CELL_W; itotalWidth; i+=CELL_W) /// TODO: i < pParent->coverX is faster + fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 0, 0); +#endif + + baseDraw(false); + draw_children(); +} + + +/* -------------------------------------------------------------------------- */ + + +int gePianoRoll::handle(int e) +{ + int ret = Fl_Group::handle(e); + + switch (e) { + case FL_PUSH: { + + /* avoid click on grey area */ + + if (Fl::event_x() >= pParent->coverX) { + ret = 1; + break; + } + + + push_y = Fl::event_y() - y(); + + if (Fl::event_button1()) { + + /* ax is driven by grid, ay by the height in px of each note */ + + int ax = Fl::event_x(); + int ay = Fl::event_y(); + + /* vertical snap */ + + int edge = (ay-y()) % CELL_H; + if (edge != 0) ay -= edge; + + /* if no overlap, add new piano item. Also check that it doesn't + * overflow on the grey area, by shifting it to the left if + * necessary. */ + + if (!cursorOnItem) { + int greyover = ax+20 - pParent->coverX-x(); + if (greyover > 0) + ax -= greyover; + add(new gePianoItem(ax, ay, ax-x(), ay-y(), nullptr, nullptr, pParent)); + redraw(); + } + } + ret = 1; + break; + } + case FL_DRAG: { + + if (Fl::event_button3()) { + + geNoteEditor *prc = (geNoteEditor*) parent(); + position(x(), Fl::event_y() - push_y); + + if (y() > prc->y()) + position(x(), prc->y()); + else + if (y() < prc->y()+prc->h()-h()) + position(x(), prc->y()+prc->h()-h()); + + prc->redraw(); + } + ret = 1; + break; + } + case FL_MOUSEWHEEL: { // nothing to do, just avoid small internal scroll + ret = 1; + break; + } + } + return ret; +} + + +/* -------------------------------------------------------------------------- */ + + +void gePianoRoll::updateActions() +{ + /* when zooming, don't delete and re-add actions, just MOVE them. This + * function shifts the action by a zoom factor. Those singlepress are + * stretched, as well */ + + gePianoItem *i; + for (int k=0; kgetFrame_a(), i->getFrame_b(), i->x()); + + int newX = x() + (i->getFrame_a() / pParent->zoom); + int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom); + if (newW < 8) + newW = 8; + i->resize(newX, i->y(), newW, i->h()); + i->redraw(); + + //gu_log("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x()); + } +} diff --git a/src/gui/elems/pianoRoll.h b/src/gui/elems/pianoRoll.h new file mode 100644 index 0000000..449d4d0 --- /dev/null +++ b/src/gui/elems/pianoRoll.h @@ -0,0 +1,84 @@ +/* ----------------------------------------------------------------------------- + * + * Giada - Your Hardcore Loopmachine + * + * ----------------------------------------------------------------------------- + * + * Copyright (C) 2010-2016 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_PIANO_ROLL_H +#define GE_PIANO_ROLL_H + + +#include +#include "baseActionEditor.h" + + +class gePianoRoll : public geBaseActionEditor +{ +private: + + enum class Notes + { + G = 1, FS = 2, F = 3, E = 4, DS = 5, D = 6, CS = 7, C = 8, B = 9, AS = 10, + A = 11, GS = 0 + }; + + /* drawSurface* + Generates a complex drawing in memory first and copy it to the screen at a + later point in time. Fl_Offscreen surface holds the necessary data. The first + call creates an offscreen surface of CELL_W pixel wide containing note values. + The second call creates another offscreen surface of CELL_W pixels wide + containing the rest of the piano roll. The latter will then be tiled during + the ::draw() call. */ + + void drawSurface1(); + void drawSurface2(); + + int push_y; + + Fl_Offscreen surface1; // notes, no repeat + Fl_Offscreen surface2; // lines, x-repeat + +public: + + static const int MAX_KEYS = 127; + static const int MAX_OCTAVES = 9; + static const int KEYS = 12; + static const int CELL_H = 18; + static const int CELL_W = 40; + + gePianoRoll(int x, int y, int w, class gdActionEditor *pParent); + + void draw(); + int handle(int e); + void updateActions(); + + /* cursorOnItem + Defines wheter the cursor is over a piano item. This value is updated by each + gePianoItem sub-widget. */ + + bool cursorOnItem; +}; + + +#endif diff --git a/src/gui/elems/ge_sampleChannel.cpp b/src/gui/elems/sampleChannel.cpp similarity index 57% rename from src/gui/elems/ge_sampleChannel.cpp rename to src/gui/elems/sampleChannel.cpp index 3838a9e..5b7e4c9 100644 --- a/src/gui/elems/ge_sampleChannel.cpp +++ b/src/gui/elems/sampleChannel.cpp @@ -31,61 +31,54 @@ #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" +#include "../../core/recorder.h" #include "../../core/graphics.h" -#include "../../core/channel.h" #include "../../core/wave.h" -#include "../../core/sampleChannel.h" -#include "../../core/midiChannel.h" -#include "../../glue/glue.h" +#include "../../glue/main.h" +#include "../../glue/io.h" #include "../../glue/channel.h" #include "../../glue/storage.h" -#include "../../utils/gui_utils.h" +#include "../../utils/gui.h" +#include "../../utils/string.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" +#include "../dialogs/gd_midiOutput.h" #include "../dialogs/gd_midiInput.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_warnings.h" #include "../dialogs/gd_browser.h" -#include "../dialogs/gd_midiOutput.h" -#include "../dialogs/gd_pluginList.h" -#include "../dialogs/gd_pluginChooser.h" -#include "ge_keyboard.h" -#include "ge_sampleChannel.h" #include "ge_status.h" #include "ge_modeBox.h" +#include "ge_keyboard.h" +#include "sampleChannel.h" extern Mixer G_Mixer; extern Conf G_Conf; +extern Recorder G_Recorder; extern Patch_DEPR_ G_Patch_DEPR_; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; -gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel *ch) - : gChannel(X, Y, W, H, CHANNEL_SAMPLE), ch(ch) +geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch) + : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch) { begin(); -#if defined(WITH_VST) - int delta = 168; // (7 widgets * 20) + (7 paddings * 4) -#else - int delta = 144; // (6 widgets * 20) + (6 paddings * 4) -#endif - - button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); - status = new gStatus(button->x()+button->w()+4, y(), 20, 20, ch); - mainButton = new gSampleChannelButton(status->x()+status->w()+4, y(), w() - delta, 20, "-- no sample --"); - modeBox = new gModeBox(mainButton->x()+mainButton->w()+4, y(), 20, 20, ch); - mute = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); - solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); - readActions = NULL; // no 'R' button - -#if defined(WITH_VST) - fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); - vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); + button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); + arm = new gClick(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm); + status = new gStatus(arm->x()+arm->w()+4, y(), 20, 20, ch); + mainButton = new geSampleChannelButton(status->x()+status->w()+4, y(), 20, 20, "-- no sample --"); + readActions = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm); + modeBox = new gModeBox(readActions->x()+readActions->w()+4, y(), 20, 20, ch); + mute = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); + solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); +#ifdef WITH_VST + fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); + vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); #else - vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); + vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); #endif end(); @@ -97,6 +90,9 @@ gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel * button->callback(cb_button, (void*)this); button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease + arm->type(FL_TOGGLE_BUTTON); + arm->callback(cb_arm, (void*)this); + #ifdef WITH_VST fx->callback(cb_openFxWindow, (void*)this); #endif @@ -109,6 +105,10 @@ gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel * mainButton->callback(cb_openMenu, (void*)this); + readActions->type(FL_TOGGLE_BUTTON); + readActions->value(ch->readActions); + readActions->callback(cb_readActions, (void*)this); + vol->callback(cb_changeVol, (void*)this); ch->guiChannel = this; @@ -118,60 +118,15 @@ gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel * /* -------------------------------------------------------------------------- */ -void gSampleChannel::cb_button (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_button(); } -void gSampleChannel::cb_mute (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_mute(); } -void gSampleChannel::cb_solo (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_solo(); } -void gSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openMenu(); } -void gSampleChannel::cb_changeVol (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_changeVol(); } -void gSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_readActions(); } -#ifdef WITH_VST -void gSampleChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openFxWindow(); } -#endif - - -/* -------------------------------------------------------------------------- */ - - -void gSampleChannel::__cb_mute() -{ - glue_setMute(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void gSampleChannel::__cb_solo() -{ - solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); -} - - -/* -------------------------------------------------------------------------- */ - - -void gSampleChannel::__cb_changeVol() -{ - glue_setChanVol(ch, vol->value()); -} +void geSampleChannel::cb_button (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); } +void geSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); } +void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); } /* -------------------------------------------------------------------------- */ -#ifdef WITH_VST -void gSampleChannel::__cb_openFxWindow() -{ - gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); -} -#endif - - -/* -------------------------------------------------------------------------- */ - - - -void gSampleChannel::__cb_button() +void geSampleChannel::__cb_button() { if (button->value()) // pushed glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); @@ -183,12 +138,12 @@ void gSampleChannel::__cb_button() /* -------------------------------------------------------------------------- */ -void gSampleChannel::__cb_openMenu() +void geSampleChannel::__cb_openMenu() { - /* if you're recording (actions or input) no menu is allowed; you can't - * do anything, especially deallocate the channel */ + /* If you're recording (input or actions) no menu is allowed; you can't do + anything, especially deallocate the channel */ - if (G_Mixer.chanInput == ch || recorder::active) + if (G_Mixer.recording || G_Recorder.active) return; /* the following is a trash workaround for a FLTK menu. We need a gMenu @@ -208,7 +163,7 @@ void gSampleChannel::__cb_openMenu() {"Volume"}, // 10 {"Start/Stop"}, // 11 {0}, // 12 - {"Clone channel"}, // 13 + {"Clone channel"}, // 13 {"Free channel"}, // 14 {"Delete channel"}, // 15 {0} @@ -228,7 +183,7 @@ void gSampleChannel::__cb_openMenu() /* no 'clear start/stop actions' for those channels in loop mode: * they cannot have start/stop actions. */ - if (ch->mode & LOOP_ANY) + if (((SampleChannel*)ch)->mode & LOOP_ANY) rclick_menu[11].deactivate(); Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); @@ -251,17 +206,17 @@ void gSampleChannel::__cb_openMenu() } if (strcmp(m->label(), "Setup MIDI input...") == 0) { - gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); + gu_openSubWindow(G_MainWin, new gdMidiInputChannel(ch), 0); return; } if (strcmp(m->label(), "Setup MIDI output...") == 0) { - gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0); + gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh((SampleChannel*) ch), 0); return; } if (strcmp(m->label(), "Edit sample...") == 0) { - gu_openSubWindow(mainWin, new gdEditor(ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor + gu_openSubWindow(G_MainWin, new gdEditor((SampleChannel*) ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor return; } @@ -291,10 +246,10 @@ void gSampleChannel::__cb_openMenu() /** FIXME - use gu_closeAllSubwindows() */ - mainWin->delSubWindow(WID_FILE_BROWSER); - mainWin->delSubWindow(WID_ACTION_EDITOR); - mainWin->delSubWindow(WID_SAMPLE_EDITOR); - mainWin->delSubWindow(WID_FX_LIST); + G_MainWin->delSubWindow(WID_FILE_BROWSER); + G_MainWin->delSubWindow(WID_ACTION_EDITOR); + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); + G_MainWin->delSubWindow(WID_FX_LIST); return; } @@ -307,9 +262,9 @@ void gSampleChannel::__cb_openMenu() if (strcmp(m->label(), "Mute") == 0) { if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?")) return; - recorder::clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF); + G_Recorder.clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF); if (!ch->hasActions) - delActionButton(); + hideActionButton(); /* TODO - set mute=false */ @@ -320,9 +275,9 @@ void gSampleChannel::__cb_openMenu() if (strcmp(m->label(), "Start/Stop") == 0) { if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?")) return; - recorder::clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN); + G_Recorder.clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN); if (!ch->hasActions) - delActionButton(); + hideActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } @@ -330,9 +285,9 @@ void gSampleChannel::__cb_openMenu() if (strcmp(m->label(), "Volume") == 0) { if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?")) return; - recorder::clearAction(ch->index, ACTION_VOLUME); + G_Recorder.clearAction(ch->index, ACTION_VOLUME); if (!ch->hasActions) - delActionButton(); + hideActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } @@ -340,14 +295,14 @@ void gSampleChannel::__cb_openMenu() if (strcmp(m->label(), "All") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; - recorder::clearChan(ch->index); - delActionButton(); + G_Recorder.clearChan(ch->index); + hideActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Edit actions...") == 0) { - gu_openSubWindow(mainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); + gu_openSubWindow(G_MainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); return; } } @@ -356,16 +311,16 @@ void gSampleChannel::__cb_openMenu() /* -------------------------------------------------------------------------- */ -void gSampleChannel::__cb_readActions() +void geSampleChannel::__cb_readActions() { - ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch); + glue_startStopReadingRecs((SampleChannel*) ch); } /* -------------------------------------------------------------------------- */ -void gSampleChannel::openBrowser(int type) +void geSampleChannel::openBrowser(int type) { gWindow *childWin = NULL; switch (type) { @@ -381,25 +336,25 @@ void gSampleChannel::openBrowser(int type) break; } if (childWin) - gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); + gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER); } /* -------------------------------------------------------------------------- */ -void gSampleChannel::refresh() +void geSampleChannel::refresh() { if (!mainButton->visible()) // mainButton invisible? status too (see below) return; setColorsByStatus(ch->status, ch->recStatus); - if (ch->wave != NULL) { - if (G_Mixer.chanInput == ch) + if (((SampleChannel*) ch)->wave != NULL) { + if (G_Mixer.recording && ch->armed) mainButton->setInputRecordMode(); - if (recorder::active) { - if (recorder::canRec(ch)) + if (G_Recorder.active) { + if (G_Recorder.canRec(ch)) mainButton->setActionRecordMode(); } status->redraw(); // status invisible? sampleButton too (see below) @@ -411,9 +366,9 @@ void gSampleChannel::refresh() /* -------------------------------------------------------------------------- */ -void gSampleChannel::reset() +void geSampleChannel::reset() { - delActionButton(true); // force==true, don't check, just remove it + hideActionButton(); mainButton->setDefaultMode("-- no sample --"); mainButton->redraw(); status->redraw(); @@ -423,7 +378,7 @@ void gSampleChannel::reset() /* -------------------------------------------------------------------------- */ -void gSampleChannel::update() +void geSampleChannel::update() { /* update sample button's label */ @@ -436,7 +391,7 @@ void gSampleChannel::update() mainButton->label("* file not found! *"); break; default: - mainButton->label(ch->wave->name.c_str()); + mainButton->label(((SampleChannel*) ch)->wave->name.c_str()); break; } @@ -445,13 +400,13 @@ void gSampleChannel::update() * button must be activated accordingly. */ if (ch->hasActions) - addActionButton(); + showActionButton(); else - delActionButton(); + hideActionButton(); /* updates modebox */ - modeBox->value(ch->mode); + modeBox->value(((SampleChannel*) ch)->mode); modeBox->redraw(); /* update volumes+mute+solo */ @@ -472,112 +427,52 @@ void gSampleChannel::update() /* -------------------------------------------------------------------------- */ -int gSampleChannel::keyPress(int e) -{ - return handleKey(e, ch->key); -} - - -/* -------------------------------------------------------------------------- */ - - -void gSampleChannel::addActionButton() +void geSampleChannel::showActionButton() { - /* quit if 'R' exists yet. */ - - if (readActions != NULL) - return; - - mainButton->size(mainButton->w()-24, mainButton->h()); - + readActions->value(((SampleChannel*) ch)->readActions); + readActions->show(); + packWidgets(); redraw(); - - readActions = new gClick(mainButton->x() + mainButton->w() + 4, - mainButton->y(), 20, 20, "", readActionOff_xpm, - readActionOn_xpm); - readActions->type(FL_TOGGLE_BUTTON); - readActions->value(ch->readActions); - readActions->callback(cb_readActions, (void*)this); - add(readActions); - - /* hard redraw: there's no other way to avoid glitches when moving - * the 'R' button */ - - mainWin->keyboard->redraw(); } /* -------------------------------------------------------------------------- */ -void gSampleChannel::delActionButton(bool force) +void geSampleChannel::hideActionButton() { - if (readActions == NULL) - return; - - /* TODO - readActions check is useless here */ - - if (!force && (readActions == NULL || ch->hasActions)) - return; - - remove(readActions); // delete from Keyboard group (FLTK) - delete readActions; // delete (C++) - readActions = NULL; - - mainButton->size(mainButton->w()+24, mainButton->h()); - mainButton->redraw(); + readActions->hide(); + packWidgets(); + redraw(); } /* -------------------------------------------------------------------------- */ -void gSampleChannel::resize(int X, int Y, int W, int H) +void geSampleChannel::resize(int X, int Y, int W, int H) { - gChannel::resize(X, Y, W, H); + geChannel::resize(X, Y, W, H); - if (w() < BREAK_FX) { + arm->hide(); + modeBox->hide(); + readActions->hide(); #ifdef WITH_VST - fx->hide(); + fx->hide(); #endif - mainButton->size(w() - BREAK_DELTA, mainButton->h()); - mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - solo->resize(mute->x()+mute->w()+4, y(), 20, 20); - - /* The followings are useless on manual resizing, but useful when a channel - * is added from a patch with a small width. */ - modeBox->hide(); - if (readActions) - readActions->hide(); - } - else - if (w() < BREAK_MODE_BOX) { + if (w() > BREAK_ARM) + arm->show(); #ifdef WITH_VST + if (w() > BREAK_FX) fx->show(); #endif - mainButton->size(w() - (BREAK_DELTA + BREAK_UNIT), mainButton->h()); - mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - solo->resize(mute->x()+mute->w()+4, y(), 20, 20); - modeBox->hide(); - } - else - if (w() < BREAK_READ_ACTIONS) { - modeBox->show(); - mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h()); - modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - if (readActions) - readActions->hide(); - } - else { - if (readActions) { - mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 3)), mainButton->h()); - readActions->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); - readActions->show(); - } - } + if (w() > BREAK_MODE_BOX) + modeBox->show(); + if (w() > BREAK_READ_ACTIONS && ch->hasActions) + readActions->show(); - gChannel::init_sizes(); + packWidgets(); } @@ -586,14 +481,14 @@ void gSampleChannel::resize(int X, int Y, int W, int H) /* -------------------------------------------------------------------------- */ -gSampleChannelButton::gSampleChannelButton(int x, int y, int w, int h, const char *l) - : gChannelButton(x, y, w, h, l) {} +geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const char *l) + : geChannelButton(x, y, w, h, l) {} /* -------------------------------------------------------------------------- */ -int gSampleChannelButton::handle(int e) +int geSampleChannelButton::handle(int e) { int ret = gClick::handle(e); switch (e) { @@ -604,11 +499,11 @@ int gSampleChannelButton::handle(int e) break; } case FL_PASTE: { - gSampleChannel *gch = (gSampleChannel*) parent(); // parent is gSampleChannel - SampleChannel *ch = gch->ch; - int result = glue_loadChannel(ch, gTrim(gStripFileUrl(Fl::event_text())).c_str()); + geSampleChannel *gch = (geSampleChannel*) parent(); // parent is geSampleChannel + SampleChannel *ch = (SampleChannel*) gch->ch; + int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str()); if (result != SAMPLE_LOADED_OK) - mainWin->keyboard->printChannelMessage(result); + G_MainWin->keyboard->printChannelMessage(result); ret = 1; break; } diff --git a/src/gui/elems/ge_sampleChannel.h b/src/gui/elems/sampleChannel.h similarity index 62% rename from src/gui/elems/ge_sampleChannel.h rename to src/gui/elems/sampleChannel.h index db5beb2..efde2a6 100644 --- a/src/gui/elems/ge_sampleChannel.h +++ b/src/gui/elems/sampleChannel.h @@ -31,72 +31,51 @@ #define GE_SAMPLE_CHANNEL_H -#include -#include -#include -#include "ge_channel.h" -#include "ge_channelButton.h" -#include "ge_mixed.h" +#include "channel.h" +#include "channelButton.h" -class gSampleChannel : public gChannel +class geSampleChannel : public geChannel { private: static void cb_button (Fl_Widget *v, void *p); - static void cb_mute (Fl_Widget *v, void *p); - static void cb_solo (Fl_Widget *v, void *p); static void cb_openMenu (Fl_Widget *v, void *p); - static void cb_changeVol (Fl_Widget *v, void *p); static void cb_readActions (Fl_Widget *v, void *p); -#ifdef WITH_VST - static void cb_openFxWindow (Fl_Widget *v, void *p); -#endif - inline void __cb_mute (); - inline void __cb_solo (); - inline void __cb_changeVol (); inline void __cb_button (); inline void __cb_openMenu (); inline void __cb_readActions (); -#ifdef WITH_VST - inline void __cb_openFxWindow(); -#endif void openBrowser(int type); public: - gSampleChannel(int x, int y, int w, int h, class SampleChannel *ch); + geSampleChannel(int x, int y, int w, int h, class SampleChannel *ch); void reset (); void update (); void refresh (); - int keyPress(int event); void resize (int x, int y, int w, int h); - /* add/delActionButton - * add or remove 'R' button when actions are available. 'Status' is - * the initial status of the button: on or off. - * If force==true remove the button with no further checks. */ + /* show/hideActionButton + Adds or removes 'R' button when actions are available. */ + + void showActionButton(); + void hideActionButton(); - void addActionButton(); - void delActionButton(bool force=false); - class gModeBox *modeBox; class gClick *readActions; - - class SampleChannel *ch; }; /* -------------------------------------------------------------------------- */ -class gSampleChannelButton : public gChannelButton +class geSampleChannelButton : public geChannelButton { public: - gSampleChannelButton(int x, int y, int w, int h, const char *l=0); + geSampleChannelButton(int x, int y, int w, int h, const char *l=0); int handle(int e); }; diff --git a/src/main.cpp b/src/main.cpp index d619c5a..a80e63b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,16 +38,20 @@ #include "core/mixer.h" #include "core/mixerHandler.h" #include "core/kernelAudio.h" +#include "core/kernelMidi.h" #include "core/recorder.h" -#include "utils/gui_utils.h" +#include "utils/gui.h" #include "gui/dialogs/gd_mainWindow.h" #include "core/pluginHost.h" /* global variables. Yeah, we are nasty */ -pthread_t t_video; +pthread_t G_videoThread; +KernelAudio G_KernelAudio; Mixer G_Mixer; +Recorder G_Recorder; +KernelMidi G_KernelMidi; bool G_quit; bool G_audio_status; bool G_midiStatus; @@ -55,18 +59,18 @@ Patch_DEPR_ G_Patch_DEPR_; Patch G_Patch; Conf G_Conf; MidiMapConf G_MidiMap; -gdMainWindow *mainWin; +gdMainWindow *G_MainWin; #ifdef WITH_VST PluginHost G_PluginHost; #endif -void *thread_video(void *arg); +void *videoThreadCb(void *arg); -int main(int argc, char **argv) { - +int main(int argc, char **argv) +{ G_quit = false; init_prepareParser(); @@ -75,7 +79,7 @@ int main(int argc, char **argv) { init_prepareKernelMIDI(); init_startGUI(argc, argv); Fl::lock(); - pthread_create(&t_video, NULL, thread_video, NULL); + pthread_create(&G_videoThread, NULL, videoThreadCb, NULL); init_startKernelAudio(); #ifdef WITH_VST @@ -88,16 +92,16 @@ int main(int argc, char **argv) { juce::shutdownJuce_GUI(); #endif - pthread_join(t_video, NULL); + pthread_join(G_videoThread, NULL); return ret; } - -void *thread_video(void *arg) { +void *videoThreadCb(void *arg) +{ if (G_audio_status) while (!G_quit) { - gu_refresh(); + gu_refreshUI(); #ifdef _WIN32 Sleep(GUI_SLEEP); #else diff --git a/src/utils/utils.cpp b/src/utils/fs.cpp similarity index 55% rename from src/utils/utils.cpp rename to src/utils/fs.cpp index 16e00f4..23b2384 100644 --- a/src/utils/utils.cpp +++ b/src/utils/fs.cpp @@ -35,29 +35,30 @@ #endif #include -#include // stat (gDirExists) +#include // stat (gu_dirExists) #include #include #include #include #include -#include #include #if defined(__APPLE__) #include // basename unix #include // getpwuid #endif #include "../core/const.h" -#include "utils.h" +#include "string.h" +#include "log.h" +#include "fs.h" using std::string; using std::vector; -bool gFileExists(const char *filename) +bool gu_fileExists(const string &filename) { - FILE *fh = fopen(filename, "rb"); + FILE *fh = fopen(filename.c_str(), "rb"); if (!fh) { return 0; } @@ -68,32 +69,26 @@ bool gFileExists(const char *filename) } -bool gFileExists(const string &filename) -{ - return gFileExists(filename.c_str()); -} - - /* -------------------------------------------------------------------------- */ -bool gIsDir(const char *path) +bool gu_isDir(const string &path) { bool ret; #if defined(__linux__) struct stat s1; - stat(path, &s1); + stat(path.c_str(), &s1); ret = S_ISDIR(s1.st_mode); #elif defined(__APPLE__) - if (strcmp(path, "")==0) + if (strcmp(path.c_str(), "") == 0) ret = false; else { struct stat s1; - stat(path, &s1); + stat(path.c_str(), &s1); ret = S_ISDIR(s1.st_mode); /* check if ret is a bundle, a special OS X folder which must be @@ -101,72 +96,53 @@ bool gIsDir(const char *path) * FIXME - consider native functions CFBundle... */ if (ret) { - string tmp = path; - tmp += "/Contents/Info.plist"; - if (gFileExists(tmp.c_str())) + if (gu_fileExists(path + "/Contents/Info.plist")) ret = false; } } #elif defined(__WIN32) - unsigned dwAttrib = GetFileAttributes(path); + unsigned dwAttrib = GetFileAttributes(path.c_str()); ret = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #endif - return ret & !gIsProject(path); + return ret & !gu_isProject(path); } -bool gIsDir(const string &path) -{ - return gIsDir(path.c_str()); -} - /* -------------------------------------------------------------------------- */ -bool gDirExists(const char *path) +bool gu_dirExists(const string &path) { struct stat st; - if (stat(path, &st) != 0 && errno == ENOENT) + if (stat(path.c_str(), &st) != 0 && errno == ENOENT) return false; return true; } -bool gDirExists(const string &path) -{ - return gDirExists(path.c_str()); -} - - /* -------------------------------------------------------------------------- */ -bool gMkdir(const char *path) +bool gu_mkdir(const string &path) { #if defined(__linux__) || defined(__APPLE__) - if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) + if (mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) #else - if (_mkdir(path) == 0) + if (_mkdir(path.c_str()) == 0) #endif return true; return false; } -bool gMkdir(const string &path) -{ - return gMkdir(path.c_str()); -} - - /* -------------------------------------------------------------------------- */ -string gBasename(const string &s) +string gu_basename(const string &s) { string out = s; out.erase(0, out.find_last_of(G_SLASH_STR) + 1); @@ -177,7 +153,7 @@ string gBasename(const string &s) /* -------------------------------------------------------------------------- */ -string gDirname(const string &path) +string gu_dirname(const string &path) { if (path.empty()) return ""; @@ -190,7 +166,7 @@ string gDirname(const string &path) /* -------------------------------------------------------------------------- */ -string gGetCurrentPath() +string gu_getCurrentPath() { char buf[PATH_MAX]; #if defined(__WIN32) @@ -207,9 +183,10 @@ string gGetCurrentPath() /* -------------------------------------------------------------------------- */ -string gGetExt(const char *file) +string gu_getExt(const string &file) { - int len = strlen(file); + // TODO - use std functions + int len = strlen(file.c_str()); int pos = len; while (pos>0) { if (file[pos] == '.') @@ -226,21 +203,7 @@ string gGetExt(const char *file) /* -------------------------------------------------------------------------- */ -string gStripExt(const char *file) -{ - int len = strlen(file); - int pos = -1; - for (int i=0; i=0) { /// TODO - use gGetSlash() -#if defined(__linux__) || defined(__APPLE__) - if (out[i] == '/') -#elif defined(_WIN32) - if (out[i] == '\\') -#endif - break; - i--; - } - - out.erase(0, i+1); // includes the '/' (or '\' on windows) - return out; -} - - - -/* -------------------------------------------------------------------------- */ - - -string gItoa(int i) -{ - std::stringstream out; - out << i; - return out.str(); -} - - -/* -------------------------------------------------------------------------- */ - - -string gTrim(const char *f) +string gu_stripFileUrl(const string &f) { string out = f; - return gTrim(out); -} - - -string gTrim(const string &s) -{ - std::size_t first = s.find_first_not_of(" \n\t"); - std::size_t last = s.find_last_not_of(" \n\t"); - return s.substr(first, last-first+1); -} - - -/* -------------------------------------------------------------------------- */ - - -string gReplace(string in, const string& search, const string& replace) -{ - size_t pos = 0; - while ((pos = in.find(search, pos)) != string::npos) { - in.replace(pos, search.length(), replace); - pos += replace.length(); - } - return in; -} - - -/* -------------------------------------------------------------------------- */ - - -string gStripFileUrl(const char *f) -{ - string out = f; - out = gReplace(out, "file://", ""); - out = gReplace(out, "%20", " "); + out = gu_replace(out, "file://", ""); + out = gu_replace(out, "%20", " "); return out; } @@ -353,7 +237,7 @@ string gStripFileUrl(const char *f) /* -------------------------------------------------------------------------- */ -string gGetHomePath() +string gu_getHomePath() { char path[PATH_MAX]; @@ -369,7 +253,7 @@ string gGetHomePath() struct passwd *p = getpwuid(getuid()); if (p == NULL) { - gLog("[gGetHomePath] unable to fetch user infos\n"); + gu_log("[gu_getHomePath] unable to fetch user infos\n"); return ""; } else { @@ -381,23 +265,3 @@ string gGetHomePath() return string(path); } - - -/* -------------------------------------------------------------------------- */ - - -void gSplit(string in, string sep, vector *v) -{ - string full = in; - string token = ""; - size_t curr = 0; - size_t next = -1; - do { - curr = next + 1; - next = full.find_first_of(sep, curr); - token = full.substr(curr, next - curr); - if (token != "") - v->push_back(token); - } - while (next != string::npos); -} diff --git a/src/utils/utils.h b/src/utils/fs.h similarity index 57% rename from src/utils/utils.h rename to src/utils/fs.h index dd6ecd0..abb9861 100644 --- a/src/utils/utils.h +++ b/src/utils/fs.h @@ -32,56 +32,36 @@ #include -#include #include -#include "log.h" using std::string; using std::vector; -bool gFileExists(const char *path); -bool gFileExists(const string &path); +bool gu_fileExists(const string &path); -bool gDirExists(const char *path); -bool gDirExists(const string &path); +bool gu_dirExists(const string &path); -bool gIsDir(const char *path); -bool gIsDir(const string &path); +bool gu_isDir(const string &path); -bool gIsProject(const string &path); +bool gu_isProject(const string &path); -bool gIsPatch(const char *path); -bool gIsPatch(const string &path); +bool gu_mkdir(const string &path); -bool gMkdir(const char *path); -bool gMkdir(const string &path); +string gu_getCurrentPath(); -string gBasename(const string &s); +string gu_getHomePath(); -string gReplace(string in, const string& search, const string& replace); +string gu_basename(const string &s); -string gDirname(const string &s); +string gu_dirname(const string &s); -string gTrim(const char *path); -string gTrim(const string &s); +string gu_getExt(const string &s); -string gGetCurrentPath(); +string gu_stripExt(const string &s); -string gGetHomePath(); +string gu_stripFileUrl(const string &s); -string gStripFileUrl(const char *path); - -string gGetExt(const char *path); - -string gStripExt(const char *path); -string gStripExt(const string &s); - -string gGetProjectName(const char *path); // TODO - useless! - -string gItoa(int i); - -void gSplit(string in, string sep, vector *v); #endif diff --git a/src/utils/gui_utils.cpp b/src/utils/gui.cpp similarity index 70% rename from src/utils/gui_utils.cpp rename to src/utils/gui.cpp index ec711d5..5daf5d5 100644 --- a/src/utils/gui_utils.cpp +++ b/src/utils/gui.cpp @@ -40,9 +40,10 @@ #include "../gui/dialogs/gd_actionEditor.h" #include "../gui/elems/ge_keyboard.h" #include "../gui/elems/ge_window.h" -#include "../gui/elems/ge_channel.h" -#include "gui_utils.h" +#include "../gui/elems/channel.h" #include "log.h" +#include "string.h" +#include "gui.h" extern Mixer G_Mixer; @@ -51,7 +52,7 @@ extern bool G_audio_status; extern Patch_DEPR_ G_patch; extern Conf G_conf; extern uint32_t G_time; -extern gdMainWindow *mainWin; +extern gdMainWindow *G_MainWin; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif @@ -60,16 +61,16 @@ extern PluginHost G_PluginHost; static int blinker = 0; -void gu_refresh() +void gu_refreshUI() { Fl::lock(); /* update dynamic elements: in and out meters, beat meter and * each channel */ - mainWin->inOut->refresh(); - mainWin->beatMeter->redraw(); - mainWin->keyboard->refreshColumns(); + G_MainWin->inOut->refresh(); + G_MainWin->beatMeter->redraw(); + G_MainWin->keyboard->refreshColumns(); /* compute timer for blinker */ @@ -98,37 +99,31 @@ int gu_getBlinker() void gu_updateControls() { - for (unsigned i=0; iguiChannel->update(); - } - mainWin->inOut->setOutVol(G_Mixer.outVol); - mainWin->inOut->setInVol(G_Mixer.inVol); + G_MainWin->inOut->setOutVol(G_Mixer.outVol); + G_MainWin->inOut->setInVol(G_Mixer.inVol); #ifdef WITH_VST - mainWin->inOut->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0); - mainWin->inOut->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0); + G_MainWin->inOut->setMasterFxOutFull(G_PluginHost.getStack(PluginHost::MASTER_OUT)->size() > 0); + G_MainWin->inOut->setMasterFxInFull(G_PluginHost.getStack(PluginHost::MASTER_IN)->size() > 0); #endif - mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); - mainWin->timing->setBpm(G_Mixer.bpm); - - /* if you reset to init state while the seq is in play: it's better to - * update the button status */ + G_MainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); + G_MainWin->timing->setBpm(G_Mixer.bpm); - mainWin->controller->updatePlay(G_Mixer.running); - mainWin->controller->updateMetronome(0); + G_MainWin->controller->updatePlay(G_Mixer.running); + G_MainWin->controller->updateMetronome(G_Mixer.metronome); } /* -------------------------------------------------------------------------- */ -void gu_update_win_label(const char *c) +void gu_updateMainWinLabel(const string &s) { - std::string out = G_APP_NAME; - out += " - "; - out += c; - mainWin->copy_label(out.c_str()); + std::string out = std::string(G_APP_NAME) + " - " + s; + G_MainWin->copy_label(out.c_str()); } @@ -138,18 +133,17 @@ void gu_update_win_label(const char *c) void gu_setFavicon(Fl_Window *w) { #if defined(__linux__) + fl_open_display(); Pixmap p, mask; - XpmCreatePixmapFromData( - fl_display, - DefaultRootWindow(fl_display), - (char **)giada_icon, - &p, - &mask, - NULL); + XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), + (char **) giada_icon, &p, &mask, NULL); w->icon((char *)p); + #elif defined(_WIN32) + w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1))); + #endif } @@ -160,7 +154,7 @@ void gu_setFavicon(Fl_Window *w) void gu_openSubWindow(gWindow *parent, gWindow *child, int id) { if (parent->hasWindow(id)) { - gLog("[GU] parent has subwindow with id=%d, deleting\n", id); + gu_log("[GU] parent has subwindow with id=%d, deleting\n", id); parent->delSubWindow(id); } child->setId(id); @@ -175,11 +169,11 @@ void gu_refreshActionEditor() { /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */ - gdActionEditor *aeditor = (gdActionEditor*) mainWin->getChild(WID_ACTION_EDITOR); + gdActionEditor *aeditor = (gdActionEditor*) G_MainWin->getChild(WID_ACTION_EDITOR); if (aeditor) { Channel *chan = aeditor->chan; - mainWin->delSubWindow(WID_ACTION_EDITOR); - gu_openSubWindow(mainWin, new gdActionEditor(chan), WID_ACTION_EDITOR); + G_MainWin->delSubWindow(WID_ACTION_EDITOR); + gu_openSubWindow(G_MainWin, new gdActionEditor(chan), WID_ACTION_EDITOR); } } @@ -204,10 +198,10 @@ void gu_closeAllSubwindows() /* don't close WID_FILE_BROWSER, because it's the caller of this * function */ - mainWin->delSubWindow(WID_ACTION_EDITOR); - mainWin->delSubWindow(WID_SAMPLE_EDITOR); - mainWin->delSubWindow(WID_FX_LIST); - mainWin->delSubWindow(WID_FX); + G_MainWin->delSubWindow(WID_ACTION_EDITOR); + G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); + G_MainWin->delSubWindow(WID_FX_LIST); + G_MainWin->delSubWindow(WID_FX); } @@ -216,9 +210,9 @@ void gu_closeAllSubwindows() string gu_removeFltkChars(const string &s) { - string out = gReplace(s, "/", "-"); - out = gReplace(out, "|", "-"); - out = gReplace(out, "&", "-"); - out = gReplace(out, "_", "-"); + string out = gu_replace(s, "/", "-"); + out = gu_replace(out, "|", "-"); + out = gu_replace(out, "&", "-"); + out = gu_replace(out, "_", "-"); return out; } diff --git a/src/utils/gui_utils.h b/src/utils/gui.h similarity index 95% rename from src/utils/gui_utils.h rename to src/utils/gui.h index 605b196..921c9ea 100644 --- a/src/utils/gui_utils.h +++ b/src/utils/gui.h @@ -1,10 +1,8 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * - * gui_utils - * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +22,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef GUI_UTILS_H #define GUI_UTILS_H @@ -52,7 +50,7 @@ using std::string; /* refresh * refresh all GUI elements. */ -void gu_refresh(); +void gu_refreshUI(); /* getBlinker * return blinker value, used to make widgets blink. */ @@ -68,7 +66,7 @@ void gu_updateControls(); /* update_win_label * update the name of the main window */ -void gu_update_win_label(const char *c); +void gu_updateMainWinLabel(const string &s); void gu_setFavicon(Fl_Window *w); diff --git a/src/utils/log.cpp b/src/utils/log.cpp index 1ebef9f..3724f03 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * log * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,27 +24,31 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #include #include #include -#include "../utils/utils.h" +#include "../utils/fs.h" #include "../core/const.h" #include "log.h" +using std::string; + + static FILE *f; static int mode; static bool stat; -int gLog_init(int m) { +int gu_logInit(int m) +{ mode = m; stat = true; if (mode == LOG_MODE_FILE) { - std::string fpath = gGetHomePath() + "/giada.log"; + string fpath = gu_getHomePath() + G_SLASH + "giada.log"; f = fopen(fpath.c_str(), "a"); if (!f) { stat = false; @@ -55,19 +59,21 @@ int gLog_init(int m) { } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gLog_close() { +void gu_logClose() +{ if (mode == LOG_MODE_FILE) fclose(f); } -/* ------------------------------------------------------------------ */ +/* -------------------------------------------------------------------------- */ -void gLog(const char *format, ...) { +void gu_log(const char *format, ...) +{ if (mode == LOG_MODE_MUTE) return; va_list args; diff --git a/src/utils/log.h b/src/utils/log.h index 285a7d6..14ece29 100644 --- a/src/utils/log.h +++ b/src/utils/log.h @@ -1,10 +1,10 @@ -/* --------------------------------------------------------------------- +/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * log * - * --------------------------------------------------------------------- + * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * @@ -24,7 +24,7 @@ * along with Giada - Your Hardcore Loopmachine. If not, see * . * - * ------------------------------------------------------------------ */ + * -------------------------------------------------------------------------- */ #ifndef __LOG_H__ @@ -34,12 +34,12 @@ /* init * init logger. Mode defines where to write the output: LOG_MODE_STDOUT, * LOG_MODE_FILE and LOG_MODE_MUTE. */ - -int gLog_init (int mode); -void gLog_close(); +int gu_logInit(int mode); -void gLog(const char *format, ...); +void gu_logClose(); + +void gu_log(const char *format, ...); #endif diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 167ed83..603693e 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -27,14 +27,15 @@ * -------------------------------------------------------------------------- */ -#include "string.h" #include +#include +#include "string.h" using std::string; -string gGetRealPath(const string &path) +string gu_getRealPath(const string &path) { string out = ""; @@ -54,3 +55,59 @@ string gGetRealPath(const string &path) } return out; } + + +/* -------------------------------------------------------------------------- */ + + +string gu_itoa(int i) +{ + std::stringstream out; + out << i; + return out.str(); +} + + +/* -------------------------------------------------------------------------- */ + + +string gu_trim(const string &s) +{ + std::size_t first = s.find_first_not_of(" \n\t"); + std::size_t last = s.find_last_not_of(" \n\t"); + return s.substr(first, last-first+1); +} + + +/* -------------------------------------------------------------------------- */ + + +string gu_replace(string in, const string &search, const string &replace) +{ + size_t pos = 0; + while ((pos = in.find(search, pos)) != string::npos) { + in.replace(pos, search.length(), replace); + pos += replace.length(); + } + return in; +} + + +/* -------------------------------------------------------------------------- */ + + +void gu_split(string in, string sep, vector *v) +{ + string full = in; + string token = ""; + size_t curr = 0; + size_t next = -1; + do { + curr = next + 1; + next = full.find_first_of(sep, curr); + token = full.substr(curr, next - curr); + if (token != "") + v->push_back(token); + } + while (next != string::npos); +} diff --git a/src/utils/string.h b/src/utils/string.h index 758b742..88df1af 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -32,14 +32,22 @@ #include -#include #include -#include "log.h" using std::string; +using std::vector; -string gGetRealPath(const string &path); +string gu_getRealPath(const string &path); + +string gu_replace(string in, const string &search, const string &replace); + +string gu_trim(const string &s); + +string gu_itoa(int i); + +void gu_split(string in, string sep, vector *v); + #endif diff --git a/tests/patch.cpp b/tests/patch.cpp index 8ff9942..991ff1f 100644 --- a/tests/patch.cpp +++ b/tests/patch.cpp @@ -69,6 +69,7 @@ TEST_CASE("Test Patch class") channel1.midiInKeyPress = UINT32_MAX; // check maximum value channel1.midiInKeyRel = 1; channel1.midiInKill = 2; + channel1.midiInArm = 11; channel1.midiInVolume = 3; channel1.midiInMute = 4; channel1.midiInSolo = 5; @@ -157,6 +158,7 @@ TEST_CASE("Test Patch class") REQUIRE(channel0.midiInKeyPress == UINT32_MAX); REQUIRE(channel0.midiInKeyRel == 1); REQUIRE(channel0.midiInKill == 2); + REQUIRE(channel0.midiInArm == 11); REQUIRE(channel0.midiInVolume == 3); REQUIRE(channel0.midiInMute == 4); REQUIRE(channel0.midiInSolo == 5); diff --git a/tests/pluginHost.cpp b/tests/pluginHost.cpp index e1f071b..3ae679c 100644 --- a/tests/pluginHost.cpp +++ b/tests/pluginHost.cpp @@ -1,6 +1,8 @@ #ifdef WITH_VST #ifdef RUN_TESTS_WITH_LOCAL_FILES +// temporarily disabled due to entangled deps (WIP) +#if 0 #include "../src/core/pluginHost.h" #include "catch.hpp" @@ -26,5 +28,7 @@ TEST_CASE("Test PluginHost class") } } +#endif + #endif #endif diff --git a/tests/utils.cpp b/tests/utils.cpp index b7c88b3..0f54920 100644 --- a/tests/utils.cpp +++ b/tests/utils.cpp @@ -1,4 +1,5 @@ -#include "../src/utils/utils.h" +#include "../src/utils/fs.h" +#include "../src/utils/string.h" #include "catch.hpp" @@ -7,27 +8,27 @@ using std::vector; TEST_CASE("Test filesystem utils") { - REQUIRE(gFileExists("giada_tests") == true); - REQUIRE(gFileExists("ghost_file") == false); - REQUIRE(gDirExists("src/") == true); - REQUIRE(gDirExists("ghost_dir/") == false); - REQUIRE(gIsDir("src/") == true); - REQUIRE(gIsDir("giada_tests") == false); - REQUIRE(gBasename("tests/utils.cpp") == "utils.cpp"); - REQUIRE(gDirname("tests/utils.cpp") == "tests"); - REQUIRE(gGetExt("tests/utils.cpp") == "cpp"); - REQUIRE(gStripExt("tests/utils.cpp") == "tests/utils"); + REQUIRE(gu_fileExists("giada_tests") == true); + REQUIRE(gu_fileExists("ghost_file") == false); + REQUIRE(gu_dirExists("src/") == true); + REQUIRE(gu_dirExists("ghost_dir/") == false); + REQUIRE(gu_isDir("src/") == true); + REQUIRE(gu_isDir("giada_tests") == false); + REQUIRE(gu_basename("tests/utils.cpp") == "utils.cpp"); + REQUIRE(gu_dirname("tests/utils.cpp") == "tests"); + REQUIRE(gu_getExt("tests/utils.cpp") == "cpp"); + REQUIRE(gu_stripExt("tests/utils.cpp") == "tests/utils"); } TEST_CASE("Test string utils") { - REQUIRE(gReplace("Giada is cool", "cool", "hot") == "Giada is hot"); - REQUIRE(gTrim(" Giada is cool ") == "Giada is cool"); - REQUIRE(gItoa(666) == "666"); + REQUIRE(gu_replace("Giada is cool", "cool", "hot") == "Giada is hot"); + REQUIRE(gu_trim(" Giada is cool ") == "Giada is cool"); + REQUIRE(gu_itoa(666) == "666"); vector v; - gSplit("Giada is cool", " ", &v); + gu_split("Giada is cool", " ", &v); REQUIRE(v.size() == 3); REQUIRE(v.at(0) == "Giada"); REQUIRE(v.at(1) == "is"); -- 2.30.2