New upstream version 0.15.3+ds1
authorIOhannes m zmölnig <zmoelnig@iem.at>
Wed, 16 Jan 2019 11:08:43 +0000 (12:08 +0100)
committerIOhannes m zmölnig <zmoelnig@iem.at>
Wed, 16 Jan 2019 11:08:43 +0000 (12:08 +0100)
165 files changed:
ChangeLog
Makefile.am
README.md
extras/giada-logo.png [new file with mode: 0644]
extras/giada-logotype.png [new file with mode: 0644]
src/core/action.h [new file with mode: 0644]
src/core/channel.cpp
src/core/channel.h
src/core/channelManager.cpp
src/core/channelManager.h
src/core/clock.cpp
src/core/conf.cpp
src/core/conf.h
src/core/const.h
src/core/init.cpp
src/core/init.h
src/core/kernelMidi.cpp
src/core/midiChannel.cpp
src/core/midiChannel.h
src/core/midiChannelProc.cpp
src/core/midiChannelProc.h
src/core/midiDispatcher.cpp
src/core/midiEvent.cpp
src/core/midiEvent.h
src/core/midiMapConf.cpp
src/core/midiMapConf.h
src/core/mixer.cpp
src/core/mixer.h
src/core/mixerHandler.cpp
src/core/mixerHandler.h
src/core/patch.cpp
src/core/patch.h
src/core/plugin.cpp
src/core/plugin.h
src/core/pluginHost.cpp
src/core/pluginHost.h
src/core/recorder.cpp
src/core/recorder.h
src/core/recorderHandler.cpp [new file with mode: 0644]
src/core/recorderHandler.h [new file with mode: 0644]
src/core/sampleChannel.cpp
src/core/sampleChannel.h
src/core/sampleChannelProc.cpp
src/core/sampleChannelProc.h
src/core/sampleChannelRec.cpp
src/core/sampleChannelRec.h
src/core/wave.cpp
src/glue/actionEditor.cpp [new file with mode: 0644]
src/glue/actionEditor.h [new file with mode: 0644]
src/glue/channel.cpp
src/glue/channel.h
src/glue/io.cpp
src/glue/io.h
src/glue/main.cpp
src/glue/main.h
src/glue/plugin.h
src/glue/recorder.cpp
src/glue/recorder.h
src/glue/sampleEditor.cpp
src/glue/sampleEditor.h
src/glue/storage.cpp
src/glue/storage.h
src/glue/transport.cpp
src/glue/transport.h
src/gui/dialogs/actionEditor/baseActionEditor.cpp
src/gui/dialogs/actionEditor/baseActionEditor.h
src/gui/dialogs/actionEditor/midiActionEditor.cpp
src/gui/dialogs/actionEditor/midiActionEditor.h
src/gui/dialogs/actionEditor/sampleActionEditor.cpp
src/gui/dialogs/actionEditor/sampleActionEditor.h
src/gui/dialogs/beatsInput.cpp
src/gui/dialogs/beatsInput.h
src/gui/dialogs/browser/browserBase.h
src/gui/dialogs/browser/browserDir.h
src/gui/dialogs/browser/browserLoad.cpp
src/gui/dialogs/browser/browserLoad.h
src/gui/dialogs/browser/browserSave.cpp
src/gui/dialogs/browser/browserSave.h
src/gui/dialogs/channelNameInput.cpp
src/gui/dialogs/channelNameInput.h
src/gui/dialogs/gd_keyGrabber.cpp
src/gui/dialogs/gd_keyGrabber.h
src/gui/dialogs/gd_mainWindow.cpp
src/gui/dialogs/midiIO/midiInputChannel.h
src/gui/dialogs/midiIO/midiOutputMidiCh.cpp
src/gui/dialogs/midiIO/midiOutputMidiCh.h
src/gui/dialogs/midiIO/midiOutputSampleCh.cpp
src/gui/dialogs/midiIO/midiOutputSampleCh.h
src/gui/dialogs/pluginChooser.cpp
src/gui/dialogs/pluginChooser.h
src/gui/dialogs/pluginList.cpp
src/gui/dialogs/pluginList.h
src/gui/dialogs/pluginWindow.cpp
src/gui/dialogs/pluginWindow.h
src/gui/dialogs/pluginWindowGUI.h
src/gui/dialogs/sampleEditor.cpp
src/gui/dialogs/sampleEditor.h
src/gui/elems/actionEditor/baseAction.cpp
src/gui/elems/actionEditor/baseAction.h
src/gui/elems/actionEditor/baseActionEditor.cpp
src/gui/elems/actionEditor/baseActionEditor.h
src/gui/elems/actionEditor/envelopeEditor.cpp
src/gui/elems/actionEditor/envelopeEditor.h
src/gui/elems/actionEditor/envelopePoint.cpp
src/gui/elems/actionEditor/envelopePoint.h
src/gui/elems/actionEditor/noteEditor.cpp
src/gui/elems/actionEditor/pianoItem.cpp
src/gui/elems/actionEditor/pianoItem.h
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/actionEditor/pianoRoll.h
src/gui/elems/actionEditor/sampleAction.cpp
src/gui/elems/actionEditor/sampleAction.h
src/gui/elems/actionEditor/sampleActionEditor.cpp
src/gui/elems/actionEditor/sampleActionEditor.h
src/gui/elems/actionEditor/velocityEditor.cpp
src/gui/elems/actionEditor/velocityEditor.h
src/gui/elems/basics/resizerBar.cpp
src/gui/elems/browser.h
src/gui/elems/mainWindow/keyboard/channel.cpp
src/gui/elems/mainWindow/keyboard/channel.h
src/gui/elems/mainWindow/keyboard/channelMode.cpp
src/gui/elems/mainWindow/keyboard/channelMode.h
src/gui/elems/mainWindow/keyboard/channelStatus.cpp
src/gui/elems/mainWindow/keyboard/channelStatus.h
src/gui/elems/mainWindow/keyboard/column.cpp
src/gui/elems/mainWindow/keyboard/column.h
src/gui/elems/mainWindow/keyboard/keyboard.cpp
src/gui/elems/mainWindow/keyboard/keyboard.h
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.h
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.h
src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp
src/gui/elems/mainWindow/mainTransport.cpp
src/gui/elems/mainWindow/mainTransport.h
src/gui/elems/midiLearner.h
src/gui/elems/plugin/pluginElement.cpp
src/gui/elems/plugin/pluginElement.h
src/gui/elems/plugin/pluginParameter.cpp
src/gui/elems/plugin/pluginParameter.h
src/gui/elems/sampleEditor/boostTool.cpp
src/gui/elems/sampleEditor/boostTool.h
src/gui/elems/sampleEditor/panTool.cpp
src/gui/elems/sampleEditor/panTool.h
src/gui/elems/sampleEditor/pitchTool.cpp
src/gui/elems/sampleEditor/pitchTool.h
src/gui/elems/sampleEditor/rangeTool.cpp
src/gui/elems/sampleEditor/rangeTool.h
src/gui/elems/sampleEditor/shiftTool.cpp
src/gui/elems/sampleEditor/shiftTool.h
src/gui/elems/sampleEditor/volumeTool.cpp
src/gui/elems/sampleEditor/volumeTool.h
src/gui/elems/sampleEditor/waveTools.cpp
src/gui/elems/sampleEditor/waveTools.h
src/gui/elems/sampleEditor/waveform.cpp
src/gui/elems/sampleEditor/waveform.h
src/gui/elems/soundMeter.cpp
src/gui/elems/soundMeter.h
src/main.cpp
src/utils/math.h
tests/audioBuffer.cpp
tests/conf.cpp
tests/patch.cpp
tests/recorder.cpp
tests/sampleChannel.cpp

index 01eb682ab7c12c0a1a8f59bda9501942488345d8..ea1d5b227f508a68c9d91001e051bc68d15f99f5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
-0.15.2 --- 
+0.15.3 --- 2018 . 12 . 24
+- Action recorder refactoring
+- Optional midimap parameters (thank you @tomek-szczesny)
+- Support for "inaudible" MIDI lightning events (thank you @tomek-szczesny)
+- Build AppImage for Linux on Travis CI instance
+- Huge optimization of the AppImage binary file
+- Fix Action Editor repaint on min/max zoom levels
+- "Resize recording" flag has been removed
+- Change text labels for channel operations
+- Smarter column assignment while loading a patch/project
+- Fix wrong resizer bar width between Action Editor widgets when zooming
+- Can't display custom channel name in Sample Channel (fixed)
+- Fix crash when cloning Sample Channel with audio data in it
+- Clone channel doesn't clone channel name (fix #219)
+
+
+0.15.2 --- 2018 . 09 . 05
 - New sample-accurate Action Editor
 - New MIDI Velocity Editor widget
 - Ability to move MIDI events vertically in piano roll (i.e. change note) 
index e101bce87af0baef4cfa7cc2564a99cf7b6a9d3a..4cb3529114bb7c371074757764ff45b8c9fc7e78 100644 (file)
@@ -15,6 +15,7 @@ sourcesCore =                            \
        src/core/const.h                       \
        src/core/types.h                       \
        src/core/range.h                       \
+       src/core/action.h                      \
        src/core/channel.h                     \
        src/core/channel.cpp                   \
        src/core/sampleChannel.h               \
@@ -33,7 +34,7 @@ sourcesCore =                            \
        src/core/conf.cpp                      \
        src/core/kernelAudio.h                 \
        src/core/kernelAudio.cpp               \
-       src/core/pluginHost.h                          \
+       src/core/pluginHost.h                      \
        src/core/pluginHost.cpp                \
        src/core/mixerHandler.h                \
        src/core/mixerHandler.cpp              \
@@ -51,6 +52,8 @@ sourcesCore =                            \
        src/core/graphics.cpp                  \
        src/core/patch.h                       \
        src/core/patch.cpp                     \
+       src/core/recorderHandler.h             \
+       src/core/recorderHandler.cpp           \
        src/core/recorder.h                    \
        src/core/recorder.cpp                  \
        src/core/mixer.h                       \
@@ -85,7 +88,9 @@ sourcesCore =                            \
        src/glue/recorder.cpp                  \
        src/glue/sampleEditor.h                \
        src/glue/sampleEditor.cpp              \
-       src/gui/dialogs/window.h                                 \
+       src/glue/actionEditor.h                \
+       src/glue/actionEditor.cpp              \
+       src/gui/dialogs/window.h               \
        src/gui/dialogs/window.cpp             \
        src/gui/dialogs/gd_keyGrabber.h        \
        src/gui/dialogs/gd_keyGrabber.cpp      \
@@ -101,11 +106,11 @@ sourcesCore =                            \
        src/gui/dialogs/bpmInput.cpp           \
        src/gui/dialogs/channelNameInput.h     \
        src/gui/dialogs/channelNameInput.cpp   \
-       src/gui/dialogs/gd_config.h                              \
+       src/gui/dialogs/gd_config.h            \
        src/gui/dialogs/gd_config.cpp          \
        src/gui/dialogs/gd_devInfo.h           \
-       src/gui/dialogs/gd_devInfo.cpp               \
-       src/gui/dialogs/pluginList.h             \
+       src/gui/dialogs/gd_devInfo.cpp         \
+       src/gui/dialogs/pluginList.h           \
        src/gui/dialogs/pluginList.cpp         \
        src/gui/dialogs/pluginWindow.h         \
        src/gui/dialogs/pluginWindow.cpp       \
@@ -280,7 +285,7 @@ sourcesCore =                            \
        src/utils/string.cpp                   \
        src/deps/rtaudio-mod/RtAudio.h         \
        src/deps/rtaudio-mod/RtAudio.cpp
-sourcesTests =                 \
+sourcesTests =                   \
        tests/main.cpp               \
        tests/conf.cpp               \
        tests/wave.cpp               \
@@ -364,7 +369,7 @@ cppFlags += -D__LINUX_ALSA__ -D__LINUX_PULSE__ -D__UNIX_JACK__
 
 ldAdd += -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
   -lpthread -ldl -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson \
-  -lfreetype
+  -lfreetype -lfontconfig -lXrender -lXfixes -lXcursor -lXinerama
 
 endif
 
index a5af7a7e50417ca19983b1e21715d8f2fc2aa4a1..91998f3428e993a34bf7f74b7729b4fe8341d5ce 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,12 +1,18 @@
-# Giada - Your Hardcore Loopmachine
+<p align="center">
+       <img src="https://raw.githubusercontent.com/monocasual/giada/master/extras/giada-logotype.png" alt="Giada - Your Hardcore Loop Machine">
+</p>
 
-Official website: http://www.giadamusic.com | Travis CI status: [![Build Status](https://travis-ci.org/monocasual/giada.svg?branch=master)](https://travis-ci.org/monocasual/giada)
+<p align="center">
+<strong>Giada - Your Hardcore Loop Machine</strong> | Official website: <a href="https://www.giadamusic.com">giadamusic.com</a> | Travis CI status: <a href="https://travis-ci.org/monocasual/giada"><img src="https://travis-ci.org/monocasual/giada.svg?branch=master" alt="Build status"></a>
+</p>
 
 ## What is Giada?
 
 Giada is a free, minimal, hardcore audio tool for DJs, live performers and electronic musicians. How does it work? Just pick up your channel, fill it with samples or MIDI events and start the show by using this tiny piece of software as a loop machine, drum machine, sequencer, live sampler or yet as a plugin/effect host. Giada aims to be a compact and portable virtual device for Linux, Mac OS X and Windows for production use and live sets.
 
-➔➔➔ [See Giada in action!](http://www.youtube.com/user/GiadaLoopMachine)
+<p align="center">
+✦✦✦ <a href="http://www.youtube.com/user/GiadaLoopMachine">See Giada in action!</a> ✦✦✦
+</p>
 
 ![Giada Loop Machine screenshot](http://giadamusic.com/public/img/screenshots/giada-loop-machine-screenshot-14-carousel.jpg)
 
diff --git a/extras/giada-logo.png b/extras/giada-logo.png
new file mode 100644 (file)
index 0000000..66b17f3
Binary files /dev/null and b/extras/giada-logo.png differ
diff --git a/extras/giada-logotype.png b/extras/giada-logotype.png
new file mode 100644 (file)
index 0000000..f9a4c02
Binary files /dev/null and b/extras/giada-logotype.png differ
diff --git a/src/core/action.h b/src/core/action.h
new file mode 100644 (file)
index 0000000..af283ed
--- /dev/null
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef G_ACTION_H
+#define G_ACTION_H
+
+
+#include "types.h"
+#include "midiEvent.h"
+
+
+namespace giada {
+namespace m
+{
+struct Action
+{
+    int       id; // For persistence only
+       int       channel;
+       Frame     frame;
+       MidiEvent event;
+    int       pluginIndex;
+    int       pluginParam;
+       const Action* prev;
+       const Action* next;
+
+    bool isVolumeEnvelope() const
+    { 
+        return event.getStatus() == MidiEvent::ENVELOPE && pluginIndex == -1; 
+    }
+};
+
+}} // giada::m::
+
+#endif
\ No newline at end of file
index 6185d748063a63228e0a7f9b8b0a58d46ffaab08..5c5e554d2176ba684658efa5ef667a0fe7efeda2 100644 (file)
@@ -39,6 +39,7 @@
 #include "wave.h"
 #include "mixer.h"
 #include "mixerHandler.h"
+#include "recorderHandler.h"
 #include "conf.h"
 #include "patch.h"
 #include "waveFx.h"
 
 
 using std::string;
-using namespace giada;
-using namespace giada::m;
 
 
+namespace giada {
+namespace m 
+{
 Channel::Channel(ChannelType type, ChannelStatus status, int bufferSize)
 :      guiChannel     (nullptr),
        type           (type),
@@ -90,12 +92,11 @@ Channel::Channel(ChannelType type, ChannelStatus status, int bufferSize)
 
 void Channel::copy(const Channel* src, pthread_mutex_t* pluginMutex)
 {
-       using namespace giada::m;
-
        key             = src->key;
        volume          = src->volume;
        volume_i        = src->volume_i;
        volume_d        = src->volume_d;
+       name            = src->name;
        pan             = src->pan;
        mute            = src->mute;
        solo            = src->solo;
@@ -114,25 +115,12 @@ void Channel::copy(const Channel* src, pthread_mutex_t* pluginMutex)
        midiOutLmute    = src->midiOutLmute;
        midiOutLsolo    = src->midiOutLsolo;
 
-       /* clone plugins */
-
 #ifdef WITH_VST
-       for (unsigned i=0; i<src->plugins.size(); i++)
-               pluginHost::clonePlugin(src->plugins.at(i), pluginHost::CHANNEL,
-                       pluginMutex, this);
+       for (Plugin* plugin : src->plugins)
+               pluginHost::clonePlugin(plugin, pluginHost::CHANNEL, pluginMutex, this);
 #endif
 
-       /* clone actions */
-
-       for (unsigned i=0; i<recorder::global.size(); i++) {
-               for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
-                       recorder::action* a = recorder::global.at(i).at(k);
-                       if (a->chan == src->index) {
-                               recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
-                               hasActions = true;
-                       }
-               }
-       }
+       hasActions = recorderHandler::cloneActions(src->index, index);
 }
 
 
@@ -157,9 +145,9 @@ void Channel::writePatch(int i, bool isProject)
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::readPatch(const string& path, int i)
+void Channel::readPatch(const string& path, const patch::channel_t& pch)
 {
-       channelManager::readPatch(this, i);
+       channelManager::readPatch(this, pch);
 }
 
 
@@ -202,15 +190,19 @@ void Channel::sendMidiLstatus()
                case ChannelStatus::OFF:
                        kernelMidi::sendMidiLightning(midiOutLplaying, midimap::stopped);
                        break;
-               case ChannelStatus::PLAY:
-                       kernelMidi::sendMidiLightning(midiOutLplaying, midimap::playing);
-                       break;
                case ChannelStatus::WAIT:
                        kernelMidi::sendMidiLightning(midiOutLplaying, midimap::waiting);
                        break;
                case ChannelStatus::ENDING:
                        kernelMidi::sendMidiLightning(midiOutLplaying, midimap::stopping);
                        break;
+               case ChannelStatus::PLAY:
+                       if ((mixer::isChannelAudible(this) && !(this->mute)) || 
+                               !midimap::isDefined(midimap::playing_inaudible))
+                               kernelMidi::sendMidiLightning(midiOutLplaying, midimap::playing);
+                       else
+                               kernelMidi::sendMidiLightning(midiOutLplaying, midimap::playing_inaudible);
+                       break;
                default:
                        break;
        }
@@ -309,5 +301,6 @@ void Channel::clearMidiBuffer()
        midiBuffer.clear();
 }
 
-
 #endif
+
+}} // giada::m::
index a827d54a3a023ce41010ac6caf21479859ff35ed..45ec277a8526acdcec8f4dd4b949709f903df490 100644 (file)
@@ -33,6 +33,7 @@
 #include <string>
 #include <pthread.h>
 #include "types.h"
+#include "patch.h"
 #include "mixer.h"
 #include "midiMapConf.h"
 #include "midiEvent.h"
 #endif
 
 
-class Plugin;
-class MidiMapConf;
 class geChannel;
 
 
+namespace giada {
+namespace m 
+{
+class Plugin;
+
 class Channel
 {
 public:
@@ -63,14 +67,14 @@ public:
        /* parseEvents
        Prepares channel for rendering. This is called on each frame. */
 
-       virtual void parseEvents(giada::m::mixer::FrameEvents fe) = 0;
+       virtual void parseEvents(mixer::FrameEvents fe) = 0;
 
        /* process
        Merges working buffers into 'out', plus plugin processing (if any). Warning:
        inBuffer might be nullptr if no input devices are available for recording. */
 
-       virtual void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in,
-               bool audible, bool running) = 0;
+       virtual void process(AudioBuffer& out, const AudioBuffer& in, bool audible, 
+               bool running) = 0;
 
        /* start
        Action to do when channel starts. doQuantize = false (don't quantize)
@@ -88,11 +92,16 @@ public:
 
        virtual void kill(int localFrame) = 0;
 
-       /* set
+       /* set mute
        What to do when channel is un/muted. */
 
        virtual void setMute(bool value) = 0;
 
+       /* set solo
+       What to do when channel is un/soloed. */
+
+       virtual void setSolo(bool value) = 0;
+
        /* empty
        Frees any associated resources (e.g. waveform for SAMPLE). */
 
@@ -136,13 +145,13 @@ public:
 
        virtual void stopInputRec(int globalFrame) {};
        
-       virtual void readPatch(const std::string& basePath, int i);
+       virtual void readPatch(const std::string& basePath, const patch::channel_t& pch);
        virtual void writePatch(int i, bool isProject);
 
        /* receiveMidi
        Receives and processes midi messages from external devices. */
 
-       virtual void receiveMidi(const giada::m::MidiEvent& midiEvent) {};
+       virtual void receiveMidi(const MidiEvent& midiEvent) {};
 
        /* calcPanning
        Given an audio channel (stereo: 0 or 1) computes the current panning value. */
@@ -191,21 +200,21 @@ public:
        Pointer to a gChannel object, part of the GUI. TODO - remove this and send
        signals instead. */
 
-  geChannel* guiChannel;
+       geChannel* guiChannel;
 
        /* buffer
        Working buffer for internal processing. */
        
-       giada::m::AudioBuffer buffer;
+       AudioBuffer buffer;
 
-       giada::ChannelType   type;
-       giada::ChannelStatus status;
-       giada::ChannelStatus recStatus;
+       ChannelType   type;
+       ChannelStatus status;
+       ChannelStatus recStatus;
 
        /* previewMode
        Whether the channel is in audio preview mode or not. */
 
-       giada::PreviewMode previewMode;
+       PreviewMode previewMode;
 
        float       pan;
        float       volume;   // global volume
@@ -221,26 +230,26 @@ public:
        the delta during volume changes (or the line slope between two volume 
        points). */
        
-       float volume_i;
-       float volume_d;
+       double volume_i;
+       double volume_d;
        
-  bool hasActions;      // has something recorded
-  bool readActions;     // read what's recorded
-  
-  bool      midiIn;               // enable midi input
-  uint32_t  midiInKeyPress;
-  uint32_t  midiInKeyRel;
-  uint32_t  midiInKill;
-  uint32_t  midiInArm;
-  uint32_t  midiInVolume;
-  uint32_t  midiInMute;
-  uint32_t  midiInSolo;
-
-  /* midiInFilter
-  Which MIDI channel should be filtered out when receiving MIDI messages. -1
-  means 'all'. */
-
-  int midiInFilter;
+       bool hasActions;      // has something recorded
+       bool readActions;     // read what's recorded
+
+       bool      midiIn;               // enable midi input
+       uint32_t  midiInKeyPress;
+       uint32_t  midiInKeyRel;
+       uint32_t  midiInKill;
+       uint32_t  midiInArm;
+       uint32_t  midiInVolume;
+       uint32_t  midiInMute;
+       uint32_t  midiInSolo;
+
+       /* midiInFilter
+       Which MIDI channel should be filtered out when receiving MIDI messages. -1
+       means 'all'. */
+
+       int midiInFilter;
 
        /*  midiOutL*
         * Enable MIDI lightning output, plus a set of midi lighting event to be sent
@@ -248,17 +257,17 @@ public:
         * else gets stripped out. */
 
        bool     midiOutL;
-  uint32_t midiOutLplaying;
-  uint32_t midiOutLmute;
-  uint32_t midiOutLsolo;
+       uint32_t midiOutLplaying;
+       uint32_t midiOutLmute;
+       uint32_t midiOutLsolo;
 
 #ifdef WITH_VST
-  std::vector <Plugin*> plugins;
+       std::vector <Plugin*> plugins;
 #endif
 
 protected:
 
-       Channel(giada::ChannelType type, giada::ChannelStatus status, int bufferSize);
+       Channel(ChannelType type, ChannelStatus status, int bufferSize);
 
 #ifdef WITH_VST
 
@@ -271,5 +280,7 @@ protected:
 #endif
 };
 
+}} // giada::m::
+
 
 #endif
index 0c3e5fdf5d3c7790aa83c221d7674f9568c7db76..d138be3454cb8205d2652e74009e4ae852a56c02 100644 (file)
@@ -37,6 +37,8 @@
 #include "midiChannel.h"
 #include "pluginHost.h"
 #include "plugin.h"
+#include "action.h"
+#include "recorderHandler.h"
 #include "channelManager.h"
 
 
@@ -49,21 +51,6 @@ namespace channelManager
 {
 namespace
 {
-void writeActions_(int chanIndex, patch::channel_t& pch)
-{
-       recorder::forEachAction([&] (const recorder::action* a) {
-               if (a->chan != chanIndex) 
-                       return;
-               pch.actions.push_back(patch::action_t { 
-                       a->type, a->frame, a->fValue, a->iValue 
-               });
-       });
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 void writePlugins_(const Channel* ch, patch::channel_t& pch)
 {
 #ifdef WITH_VST
@@ -89,10 +76,8 @@ void writePlugins_(const Channel* ch, patch::channel_t& pch)
 
 void readActions_(Channel* ch, const patch::channel_t& pch)
 {
-       for (const patch::action_t& ac : pch.actions) {
-               recorder::rec(ch->index, ac.type, ac.frame, ac.iValue, ac.fValue);
-               ch->hasActions = true;
-       }
+       recorderHandler::readPatch(pch.actions);
+       ch->hasActions = pch.actions.size() > 0;
 }
 
 
@@ -132,13 +117,12 @@ void readPlugins_(Channel* ch, const patch::channel_t& pch)
 /* -------------------------------------------------------------------------- */
 
 
-int create(ChannelType type, int bufferSize, bool inputMonitorOn, Channel** out)
+Channel* create(ChannelType type, int bufferSize, bool inputMonitorOn)
 {
        if (type == ChannelType::SAMPLE)
-               *out = new SampleChannel(inputMonitorOn, bufferSize);
+               return new SampleChannel(inputMonitorOn, bufferSize);
        else
-               *out = new MidiChannel(bufferSize);
-       return G_RES_OK;
+               return new MidiChannel(bufferSize);
 }
 
 
@@ -173,7 +157,7 @@ int writePatch(const Channel* ch, bool isProject)
        pch.midiOutLmute    = ch->midiOutLmute;
        pch.midiOutLsolo    = ch->midiOutLsolo;
 
-       writeActions_(ch->index, pch);
+       recorderHandler::writePatch(ch->index, pch.actions);
        writePlugins_(ch, pch);
 
        patch::channels.push_back(pch);
@@ -223,10 +207,8 @@ void writePatch(const SampleChannel* ch, bool isProject, int index)
 /* -------------------------------------------------------------------------- */
 
 
-void readPatch(Channel* ch, int i)
+void readPatch(Channel* ch, const patch::channel_t& pch)
 {
-       const patch::channel_t& pch = patch::channels.at(i);
-
        ch->key             = pch.key;
        ch->armed           = pch.armed;
        ch->type            = static_cast<ChannelType>(pch.type);
@@ -257,21 +239,19 @@ void readPatch(Channel* ch, int i)
 /* -------------------------------------------------------------------------- */
 
 
-void readPatch(SampleChannel* ch, const string& basePath, int i)
+void readPatch(SampleChannel* ch, const string& basePath, const patch::channel_t& pch)
 {
-       const patch::channel_t& pch = patch::channels.at(i);
-
        ch->mode              = static_cast<ChannelMode>(pch.mode);
        ch->readActions       = pch.recActive;
        ch->recStatus         = pch.recActive ? ChannelStatus::PLAY : ChannelStatus::OFF;
        ch->midiInVeloAsVol   = pch.midiInVeloAsVol;
        ch->midiInReadActions = pch.midiInReadActions;
        ch->midiInPitch       = pch.midiInPitch;
-  ch->inputMonitor      = pch.inputMonitor;
+       ch->inputMonitor      = pch.inputMonitor;
        ch->setBoost(pch.boost);
 
-  Wave* w = nullptr;
-  int res = waveManager::create(basePath + pch.samplePath, &w); 
+       Wave* w = nullptr;
+       int res = waveManager::create(basePath + pch.samplePath, &w); 
 
        if (res == G_RES_OK) {
                ch->pushWave(w);
@@ -293,10 +273,8 @@ void readPatch(SampleChannel* ch, const string& basePath, int i)
 /* -------------------------------------------------------------------------- */
 
 
-void readPatch(MidiChannel* ch, int i)
+void readPatch(MidiChannel* ch, const patch::channel_t& pch)
 {
-       const patch::channel_t& pch = patch::channels.at(i);
-
        ch->midiOut     = pch.midiOut;
        ch->midiOutChan = pch.midiOutChan;      
 }
index 327e27b45722a835b8c728b70fda34c3a17d6b11..d9fd4905c057277e8012c62ec9351118eaef11f0 100644 (file)
 #include "types.h"
 
 
+namespace giada {
+namespace m 
+{
 class Channel;
 class SampleChannel;
 class MidiChannel;
 
-
-namespace giada {
-namespace m {
+namespace patch
+{
+struct channel_t;
+}
 namespace channelManager
 {
-int create(ChannelType type, int bufferSize, bool inputMonitorOn, Channel** out);
+Channel* create(ChannelType type, int bufferSize, bool inputMonitorOn);
 
 int  writePatch(const Channel* ch, bool isProject);
 void writePatch(const SampleChannel* ch, bool isProject, int index);
 void writePatch(const MidiChannel* ch, bool isProject, int index);
 
-void readPatch(Channel* ch, int index);
-void readPatch(SampleChannel* ch, const std::string& basePath, int index);
-void readPatch(MidiChannel* ch, int index);
+void readPatch(Channel* ch, const patch::channel_t& pch);
+void readPatch(SampleChannel* ch, const std::string& basePath, const patch::channel_t& pch);
+void readPatch(MidiChannel* ch, const patch::channel_t& pch);
 }}}; // giada::m::channelManager
 
 
index 66abecc412351e9c1d783b30f5c4d5565c9116a1..ea6dfbe62cb19b17b3fa46a65b697d7e114e6bb2 100644 (file)
@@ -340,11 +340,11 @@ void recvJackSync()
        if (jackState.running != jackStatePrev.running) {
                if (jackState.running) {
                        if (!isRunning())
-                               glue_startSeq(false); // not from UI
+                               c::transport::startSeq(false); // not from UI
                }
                else {
                        if (isRunning())
-                               glue_stopSeq(false); // not from UI
+                               c::transport::stopSeq(false); // not from UI
                }
        }
        if (jackState.bpm != jackStatePrev.bpm)
@@ -352,7 +352,7 @@ void recvJackSync()
                        glue_setBpm(jackState.bpm);
 
        if (jackState.frame == 0 && jackState.frame != jackStatePrev.frame)
-               glue_rewindSeq(false, false);  // not from UI, don't notify jack (avoid loop)
+               c::transport::rewindSeq(false, false);  // not from UI, don't notify jack (avoid loop)
 
        jackStatePrev = jackState;
 }
index 1185eda706465a6c9fc0b6c4cea49277c7a39c3e..975543cb3d0ab5b90fe7c9f9984103b5b7c249fe 100644 (file)
@@ -185,7 +185,6 @@ uint32_t midiInMetronome  = 0x0;
 bool recsStopOnChanHalt    = false;
 bool chansStopOnSeqHalt    = false;
 bool treatRecsAsLoops      = false;
-bool resizeRecordings      = true;
 bool inputMonitorDefaultOn = false;
 
 string pluginPath = "";
@@ -345,7 +344,6 @@ int read()
        if (!storager::setBool(jRoot, CONF_KEY_RECS_STOP_ON_CHAN_HALT, recsStopOnChanHalt)) return 0;
        if (!storager::setBool(jRoot, CONF_KEY_CHANS_STOP_ON_SEQ_HALT, chansStopOnSeqHalt)) return 0;
        if (!storager::setBool(jRoot, CONF_KEY_TREAT_RECS_AS_LOOPS, treatRecsAsLoops)) return 0;
-       if (!storager::setBool(jRoot, CONF_KEY_RESIZE_RECORDINGS, resizeRecordings)) return 0;
        if (!storager::setBool(jRoot, CONF_KEY_INPUT_MONITOR_DEFAULT_ON, inputMonitorDefaultOn)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_PLUGINS_PATH, pluginPath)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_PATCHES_PATH, patchPath)) return 0;
@@ -457,7 +455,6 @@ int write()
        json_object_set_new(jRoot, CONF_KEY_RECS_STOP_ON_CHAN_HALT,    json_boolean(recsStopOnChanHalt));
        json_object_set_new(jRoot, CONF_KEY_CHANS_STOP_ON_SEQ_HALT,    json_boolean(chansStopOnSeqHalt));
        json_object_set_new(jRoot, CONF_KEY_TREAT_RECS_AS_LOOPS,       json_boolean(treatRecsAsLoops));
-       json_object_set_new(jRoot, CONF_KEY_RESIZE_RECORDINGS,         json_boolean(resizeRecordings));
        json_object_set_new(jRoot, CONF_KEY_INPUT_MONITOR_DEFAULT_ON,  json_boolean(inputMonitorDefaultOn));
        json_object_set_new(jRoot, CONF_KEY_PLUGINS_PATH,              json_string(pluginPath.c_str()));
        json_object_set_new(jRoot, CONF_KEY_PATCHES_PATH,              json_string(patchPath.c_str()));
index 7b9a83bf9e023a3b4718922927a083c281cd6838..dd2c53b3c3c0a674fdb3bfb49031cb255dae2216 100644 (file)
@@ -83,7 +83,6 @@ extern uint32_t midiInBeatHalf;
 extern bool recsStopOnChanHalt;
 extern bool chansStopOnSeqHalt;
 extern bool treatRecsAsLoops;
-extern bool resizeRecordings;
 extern bool inputMonitorDefaultOn;
 
 extern std::string pluginPath;
index 2e244b89e4989410ae7e860e37076c778d88dfa8..81e38c91fab5fb35f286b52530b8ae22fce71901 100644 (file)
 
 /* -- version --------------------------------------------------------------- */
 #define G_APP_NAME      "Giada"
-#define G_VERSION_STR   "0.15.2"
+#define G_VERSION_STR   "0.15.3"
 #define G_VERSION_MAJOR 0
 #define G_VERSION_MINOR 15
-#define G_VERSION_PATCH 2
+#define G_VERSION_PATCH 3
 
 #define CONF_FILENAME "giada.conf"
 
 
 
 /* -- MIN/MAX values -------------------------------------------------------- */
-#define G_MIN_BPM           20.0f
-#define G_MIN_BPM_STR       "20.0"
-#define G_MAX_BPM           999.0f
-#define G_MAX_BPM_STR       "999.0"
-#define G_MAX_BEATS                              32
-#define G_MAX_BARS                               32
-#define G_MAX_QUANTIZE      8
-#define G_MIN_DB_SCALE      60.0f
-#define G_MIN_COLUMN_WIDTH  140
-#define G_MAX_BOOST_DB      20.0f
-#define G_MIN_PITCH         0.1f
-#define G_MAX_PITCH         4.0f
-#define G_MAX_GRID_VAL      64
-#define G_MIN_BUF_SIZE      8
-#define G_MAX_BUF_SIZE      4096
-#define G_MIN_GUI_WIDTH     816
-#define G_MIN_GUI_HEIGHT    510
-#define G_MAX_IO_CHANS      2
-#define G_MAX_VELOCITY      0x7F
-#define G_MAX_MIDI_CHANS    16
+constexpr float G_MIN_BPM          = 20.0f;
+constexpr auto  G_MIN_BPM_STR      = "20.0";
+constexpr float G_MAX_BPM          = 999.0f;
+constexpr auto  G_MAX_BPM_STR      = "999.0";
+constexpr int   G_MAX_BEATS        = 32;
+constexpr int   G_MAX_BARS         = 32;
+constexpr int   G_MAX_QUANTIZE     = 8;
+constexpr float G_MIN_DB_SCALE     = 60.0f;
+constexpr int   G_MIN_COLUMN_WIDTH = 140;
+constexpr float G_MAX_BOOST_DB     = 20.0f;
+constexpr float G_MIN_PITCH        = 0.1f;
+constexpr float G_MAX_PITCH        = 4.0f;
+constexpr int   G_MAX_GRID_VAL     = 64;
+constexpr int   G_MIN_BUF_SIZE     = 8;
+constexpr int   G_MAX_BUF_SIZE     = 4096;
+constexpr int   G_MIN_GUI_WIDTH    = 816;
+constexpr int   G_MIN_GUI_HEIGHT   = 510;
+constexpr int   G_MAX_IO_CHANS     = 2;
+constexpr int   G_MAX_VELOCITY     = 0x7F;
+constexpr int   G_MAX_MIDI_CHANS   = 16;
+constexpr int   G_MAX_POLYPHONY    = 32;
 
 
 
 /* -- kernel audio ---------------------------------------------------------- */
-#define G_SYS_API_NONE         0x00  // 0000 0000
-#define G_SYS_API_JACK         0x01  // 0000 0001
-#define G_SYS_API_ALSA         0x02  // 0000 0010
-#define G_SYS_API_DS                   0x04  // 0000 0100
-#define G_SYS_API_ASIO         0x08  // 0000 1000
-#define G_SYS_API_CORE         0x10  // 0001 0000
+#define G_SYS_API_NONE    0x00  // 0000 0000
+#define G_SYS_API_JACK    0x01  // 0000 0001
+#define G_SYS_API_ALSA    0x02  // 0000 0010
+#define G_SYS_API_DS      0x04  // 0000 0100
+#define G_SYS_API_ASIO    0x08  // 0000 1000
+#define G_SYS_API_CORE    0x10  // 0001 0000
 #define G_SYS_API_PULSE   0x20  // 0010 0000
 #define G_SYS_API_WASAPI  0x40  // 0100 0000
 #define G_SYS_API_ANY     0x7F  // 0111 1111
 
 
 /* -- kernel midi ----------------------------------------------------------- */
-#define G_MIDI_API_JACK                0x01  // 0000 0001
-#define G_MIDI_API_ALSA                0x02  // 0000 0010
+#define G_MIDI_API_JACK   0x01  // 0000 0001
+#define G_MIDI_API_ALSA   0x02  // 0000 0010
 
 
 
@@ -261,30 +262,13 @@ it drives knobs, volume, faders and such. */
 #define MIDI_STOP           0xFC
 #define MIDI_EOX            0xF7  // end of sysex
 
-/* channels */
-
-#define MIDI_CHAN_0         0x00 << 24
-#define MIDI_CHAN_1         0x01 << 24
-#define MIDI_CHAN_2         0x02 << 24
-#define MIDI_CHAN_3         0x03 << 24
-#define MIDI_CHAN_4         0x04 << 24
-#define MIDI_CHAN_5         0x05 << 24
-#define MIDI_CHAN_6         0x06 << 24
-#define MIDI_CHAN_7         0x07 << 24
-#define MIDI_CHAN_8         0x08 << 24
-#define MIDI_CHAN_9         0x09 << 24
-#define MIDI_CHAN_10        0x0A << 24
-#define MIDI_CHAN_11        0x0B << 24
-#define MIDI_CHAN_12        0x0C << 24
-#define MIDI_CHAN_13        0x0D << 24
-#define MIDI_CHAN_14        0x0E << 24
-#define MIDI_CHAN_15        0x0F << 24
-
-const int MIDI_CHANS[G_MAX_MIDI_CHANS] = {
-       MIDI_CHAN_0,  MIDI_CHAN_1,      MIDI_CHAN_2,  MIDI_CHAN_3,
-       MIDI_CHAN_4,  MIDI_CHAN_5,      MIDI_CHAN_6,  MIDI_CHAN_7,
-       MIDI_CHAN_8,  MIDI_CHAN_9,      MIDI_CHAN_10, MIDI_CHAN_11,
-       MIDI_CHAN_12, MIDI_CHAN_13,     MIDI_CHAN_14, MIDI_CHAN_15
+/* Channels */
+
+constexpr int G_MIDI_CHANS[G_MAX_MIDI_CHANS] = {
+       0x00 << 24,  0x01 << 24,  0x02 << 24,  0x03 << 24,
+       0x04 << 24,  0x05 << 24,  0x06 << 24,  0x07 << 24,
+       0x08 << 24,  0x09 << 24,  0x0A << 24,  0x0B << 24,
+       0x0C << 24,  0x0D << 24,  0x0E << 24,  0x0F << 24
 };
 
 /* midi sync constants */
@@ -367,6 +351,13 @@ const int MIDI_CHANS[G_MAX_MIDI_CHANS] = {
 #define PATCH_KEY_COLUMN_WIDTH                 "width"
 #define PATCH_KEY_COLUMN_CHANNELS              "channels"
 
+#define G_PATCH_KEY_ACTION_ID                  "id"
+#define G_PATCH_KEY_ACTION_CHANNEL             "channel"     
+#define G_PATCH_KEY_ACTION_FRAME               "frame"   
+#define G_PATCH_KEY_ACTION_EVENT               "event"   
+#define G_PATCH_KEY_ACTION_PREV                "prev"  
+#define G_PATCH_KEY_ACTION_NEXT                "next"
+
 /* JSON config keys */
 
 #define CONF_KEY_HEADER                   "header"
@@ -402,7 +393,6 @@ const int MIDI_CHANS[G_MAX_MIDI_CHANS] = {
 #define CONF_KEY_RECS_STOP_ON_CHAN_HALT   "recs_stop_on_chan_halt"
 #define CONF_KEY_CHANS_STOP_ON_SEQ_HALT   "chans_stop_on_seq_halt"
 #define CONF_KEY_TREAT_RECS_AS_LOOPS      "treat_recs_as_loops"
-#define CONF_KEY_RESIZE_RECORDINGS        "resize_recordings"
 #define CONF_KEY_INPUT_MONITOR_DEFAULT_ON "input_monitor_default_on"
 #define CONF_KEY_PLUGINS_PATH             "plugins_path"
 #define CONF_KEY_PATCHES_PATH             "patches_path"
@@ -460,18 +450,19 @@ const int MIDI_CHANS[G_MAX_MIDI_CHANS] = {
 
 /* JSON midimaps keys */
 
-#define MIDIMAP_KEY_BRAND          "brand"
-#define MIDIMAP_KEY_DEVICE         "device"
-#define MIDIMAP_KEY_INIT_COMMANDS  "init_commands"
-#define MIDIMAP_KEY_MUTE_ON        "mute_on"
-#define MIDIMAP_KEY_MUTE_OFF       "mute_off"
-#define MIDIMAP_KEY_SOLO_ON        "solo_on"
-#define MIDIMAP_KEY_SOLO_OFF       "solo_off"
-#define MIDIMAP_KEY_WAITING        "waiting"
-#define MIDIMAP_KEY_PLAYING        "playing"
-#define MIDIMAP_KEY_STOPPING       "stopping"
-#define MIDIMAP_KEY_STOPPED        "stopped"
-#define MIDIMAP_KEY_CHANNEL        "channel"
-#define MIDIMAP_KEY_MESSAGE        "message"
+#define MIDIMAP_KEY_BRAND                   "brand"
+#define MIDIMAP_KEY_DEVICE                  "device"
+#define MIDIMAP_KEY_INIT_COMMANDS           "init_commands"
+#define MIDIMAP_KEY_MUTE_ON                 "mute_on"
+#define MIDIMAP_KEY_MUTE_OFF                "mute_off"
+#define MIDIMAP_KEY_SOLO_ON                 "solo_on"
+#define MIDIMAP_KEY_SOLO_OFF                "solo_off"
+#define MIDIMAP_KEY_WAITING                 "waiting"
+#define MIDIMAP_KEY_PLAYING                 "playing"
+#define MIDIMAP_KEY_PLAYING_INAUDIBLE       "playing_inaudible"
+#define MIDIMAP_KEY_STOPPING                "stopping"
+#define MIDIMAP_KEY_STOPPED                 "stopped"
+#define MIDIMAP_KEY_CHANNEL                 "channel"
+#define MIDIMAP_KEY_MESSAGE                 "message"
 
 #endif
index f9cac87fd1381c68165af08b95479f5c026812d8..e03ff650af28951d74bda9b95566efb800aa46e7 100644 (file)
@@ -25,6 +25,7 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <thread>
 #include <ctime>
 #ifdef __APPLE__
        #include <pwd.h>
 #if defined(__linux__) && defined(WITH_VST)
        #include <X11/Xlib.h> // For XInitThreads
 #endif
+#include <FL/Fl.H>
 #include "../utils/log.h"
 #include "../utils/fs.h"
+#include "../utils/time.h"
 #include "../utils/gui.h"
 #include "../gui/dialogs/gd_mainWindow.h"
 #include "../gui/dialogs/gd_warnings.h"
 #include "../glue/main.h"
-#include "init.h"
 #include "mixer.h"
 #include "wave.h"
 #include "const.h"
 #include "midiMapConf.h"
 #include "kernelMidi.h"
 #include "kernelAudio.h"
+#include "init.h"
+
 
+extern std::atomic<bool> G_quit;
+extern gdMainWindow*     G_MainWin;
 
-extern bool                               G_quit;
-extern gdMainWindow *G_MainWin;
 
+namespace giada {
+namespace m {
+namespace init
+{
+namespace
+{
+std::thread videoThread;
 
-using namespace giada::m;
 
+/* -------------------------------------------------------------------------- */
 
-void init_prepareParser()
+
+void videoThreadCallback_()
 {
-       time_t t;
-  time (&t);
-       gu_log("[init] Giada " G_VERSION_STR " - %s", ctime(&t));
+       while (G_quit.load() == false) {
+               if (m::kernelAudio::getStatus())
+                       gu_refreshUI();
+               u::time::sleep(G_GUI_REFRESH_RATE);
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
 
-       conf::read();
-       patch::init();
 
+void initConf_()
+{
+       if (!conf::read())
+               gu_log("[init] Can't read configuration file! Using default values\n");
+       
+       patch::init();
+       midimap::init();
+       midimap::setDefault();
+       
        if (!gu_logInit(conf::logMode))
                gu_log("[init] log init failed! Using default stdout\n");
 
-       gu_log("[init] configuration file ready\n");
+       if (midimap::read(conf::midiMapPath) != MIDIMAP_READ_OK)
+               gu_log("[init] MIDI map read failed!\n");
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void init_prepareKernelAudio()
+void initAudio_()
 {
   kernelAudio::openDevice();
   clock::init(conf::samplerate, conf::midiTCfps);
        mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
-       recorder::init();
+       recorder::init(&mixer::mutex);
 
 #ifdef WITH_VST
 
@@ -101,38 +127,33 @@ void init_prepareKernelAudio()
 
 #endif
 
+       if (!kernelAudio::getStatus())
+               return;
+
+       kernelAudio::startStream();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void init_prepareKernelMIDI()
+void initMIDI_()
 {
        kernelMidi::setApi(conf::midiSystem);
        kernelMidi::openOutDevice(conf::midiPortOut);
-       kernelMidi::openInDevice(conf::midiPortIn);
+       kernelMidi::openInDevice(conf::midiPortIn);     
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void init_prepareMidiMap()
+void initGUI_(int argc, char** argv)
 {
-       midimap::init();
-       midimap::setDefault();
+       /* This enables the FLTK lock and start the runtime multithreading support. */
 
-       if (midimap::read(conf::midiMapPath) != MIDIMAP_READ_OK)
-               gu_log("[init_prepareMidiMap] MIDI map read failed!\n");
-}
+       Fl::lock();
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void init_startGUI(int argc, char** argv)
-{
        /* This is of paramount importance on Linux with VST enabled, otherwise many
        plug-ins go nuts and crash hard. It seems that some plug-ins or our Juce-based
        PluginHost use Xlib concurrently. */
@@ -147,71 +168,86 @@ void init_startGUI(int argc, char** argv)
 
   gu_updateMainWinLabel(patch::name == "" ? G_DEFAULT_PATCH_NAME : patch::name);
 
-       /* never update the GUI elements if kernelAudio::getStatus() is bad, segfaults
-        * are around the corner */
-
-       if (kernelAudio::getStatus())
-               gu_updateControls();
-  else
+       if (!kernelAudio::getStatus())
                gdAlert("Your soundcard isn't configured correctly.\n"
                        "Check the configuration and restart Giada.");
+
+       gu_updateControls();
+       
+       videoThread = std::thread(videoThreadCallback_);
 }
 
+
 /* -------------------------------------------------------------------------- */
 
 
-void init_startKernelAudio()
+void shutdownAudio_()
 {
-       if (kernelAudio::getStatus())
-               kernelAudio::startStream();
+#ifdef WITH_VST
+
+       pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex);
+  pluginHost::close();
+       gu_log("[init] PluginHost cleaned up\n");
+
+#endif
+
+       if (kernelAudio::getStatus()) {
+               kernelAudio::closeDevice();
+               gu_log("[init] KernelAudio closed\n");
+               mixer::close();
+               gu_log("[init] Mixer closed\n");
+       }
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void init_shutdown()
+void shutdownGUI_()
 {
-       G_quit = true;
+       gu_closeAllSubwindows();
+       videoThread.join();     
 
-       /* store position and size of the main window for the next startup */
+       gu_log("[init] All subwindows and UI thread closed\n");
+}
+} // {anonymous}
 
-       conf::mainWindowX = G_MainWin->x();
-       conf::mainWindowY = G_MainWin->y();
-       conf::mainWindowW = G_MainWin->w();
-       conf::mainWindowH = G_MainWin->h();
 
-       /* close any open subwindow, especially before cleaning PluginHost to
-        * avoid mess */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
-       gu_closeAllSubwindows();
-       gu_log("[init] all subwindows closed\n");
 
-       /* write configuration file */
+void startup(int argc, char** argv)
+{
+       time_t t;
+  time (&t);
+       gu_log("[init] Giada " G_VERSION_STR " - %s", ctime(&t));
 
-       if (!conf::write())
-               gu_log("[init] error while saving configuration file!\n");
-       else
-               gu_log("[init] configuration saved\n");
+       initConf_();
+       initAudio_();
+       initMIDI_();
+       initGUI_(argc, argv);
+}
 
-       recorder::clearAll();
-       gu_log("[init] Recorder cleaned up\n");
 
-#ifdef WITH_VST
+/* -------------------------------------------------------------------------- */
 
-       pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex);
-  pluginHost::close();
-       gu_log("[init] PluginHost cleaned up\n");
 
-#endif
+void shutdown()
+{
+       G_quit.store(true);
 
-       if (kernelAudio::getStatus()) {
-               kernelAudio::closeDevice();
-               gu_log("[init] KernelAudio closed\n");
-               mixer::close();
-               gu_log("[init] Mixer closed\n");
-       }
+       shutdownGUI_();
+
+       if (!conf::write())
+               gu_log("[init] error while saving configuration file!\n");
+       else
+               gu_log("[init] configuration saved\n");
+
+       shutdownAudio_();
 
        gu_log("[init] Giada " G_VERSION_STR " closed\n\n");
        gu_logClose();
 }
+}}} // giada::m::init
\ No newline at end of file
index 8e10de6f3e7af1eaafd00213d195b1df2d2f5765..27a5f6e941afef33e018f25b63de3bacca35bfda 100644 (file)
 #define G_INIT_H
 
 
-void init_prepareParser();
-void init_startGUI(int argc, char** argv);
-void init_prepareKernelAudio();
-void init_prepareKernelMIDI();
-void init_prepareMidiMap();
-void init_startKernelAudio();
-void init_shutdown();
-
+namespace giada {
+namespace m {
+namespace init
+{
+void startup(int argc, char** argv);
+void shutdown();
+}}} // giada::m::init
 
 #endif
index 52f760bdd47931b4206b5f410c527bf1ef559f93..485f7c1d2a0fd1defd81928ba1466c10679db7ab 100644 (file)
@@ -77,7 +77,7 @@ void sendMidiLightningInitMsgs()
                midimap::message_t msg = midimap::initCommands.at(i);
                if (msg.value != 0x0 && msg.channel != -1) {
                        gu_log("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", msg.channel, msg.value);
-                       send(msg.value | MIDI_CHANS[msg.channel]);
+                       send(msg.value | G_MIDI_CHANS[msg.channel]);
                }
        }
 }
@@ -258,6 +258,14 @@ void send(int b1, int b2, int b3)
 
 void sendMidiLightning(uint32_t learn, const midimap::message_t& msg)
 {
+       // Skip lightning message if not defined in midi map
+
+       if (!midimap::isDefined(msg))
+       {
+               gu_log("[KM] message skipped (not defined in midimap)");
+               return;
+       }
+
        gu_log("[KM] learn=%#X, chan=%d, msg=%#X, offset=%d\n", learn, msg.channel, 
                msg.value, msg.offset);
 
index 3dd4867d91d11a97d503e58a976e3f9d5e7300c6..7cc871f278d47f0924ef111da7421949d1a285cd 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include "../utils/log.h"
+#include "recorder.h"
 #include "midiChannelProc.h"
 #include "channelManager.h"
 #include "channel.h"
+#include "recorderHandler.h"
+#include "action.h"
 #include "patch.h"
 #include "const.h"
-#include "clock.h"
 #include "conf.h"
 #include "mixer.h"
 #include "pluginHost.h"
 
 
 using std::string;
-using namespace giada;
-using namespace giada::m;
 
 
+namespace giada {
+namespace m 
+{
 MidiChannel::MidiChannel(int bufferSize)
-       : Channel    (ChannelType::MIDI, ChannelStatus::OFF, bufferSize),
+       : Channel      (ChannelType::MIDI, ChannelStatus::OFF, bufferSize),
                midiOut    (false),
-               midiOutChan(MIDI_CHANS[0])
+               midiOutChan(G_MIDI_CHANS[0])
 {
 }
 
@@ -75,8 +79,8 @@ void MidiChannel::parseEvents(mixer::FrameEvents fe)
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::process(giada::m::AudioBuffer& out
-       const giada::m::AudioBuffer& in, bool audible, bool running)
+void MidiChannel::process(AudioBuffer& out, const AudioBuffer& in, bool audible
+       bool running)
 {
        midiChannelProc::process(this, out, in, audible);
 }
@@ -130,10 +134,19 @@ void MidiChannel::setMute(bool value)
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::readPatch(const string& basePath, int i)
+void MidiChannel::setSolo(bool value)
 {
-       Channel::readPatch("", i);
-       channelManager::readPatch(this, i);
+       midiChannelProc::setSolo(this, value);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiChannel::readPatch(const string& basePath, const patch::channel_t& pch)
+{
+       Channel::readPatch("", pch);
+       channelManager::readPatch(this, pch);
 }
 
 
@@ -176,26 +189,16 @@ void MidiChannel::empty()
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::sendMidi(recorder::action* a, int localFrame)
+void MidiChannel::sendMidi(const Action* a, int localFrame)
 {
        if (isPlaying() && !mute) {
-               if (midiOut)
-                       kernelMidi::send(a->iValue | MIDI_CHANS[midiOutChan]);
-
+               if (midiOut) {
+                       MidiEvent event = a->event;
+                       event.setChannel(midiOutChan);
+                       kernelMidi::send(event.getRaw());
+               }
 #ifdef WITH_VST
-               addVstMidiEvent(a->iValue, localFrame);
-#endif
-       }
-}
-
-
-void MidiChannel::sendMidi(uint32_t data)
-{
-       if (isPlaying() && !mute) {
-               if (midiOut)
-                       kernelMidi::send(data | MIDI_CHANS[midiOutChan]);
-#ifdef WITH_VST
-               addVstMidiEvent(data, 0);
+               addVstMidiEvent(a->event.getRaw(), localFrame);
 #endif
        }
 }
@@ -206,31 +209,29 @@ void MidiChannel::sendMidi(uint32_t data)
 
 void MidiChannel::receiveMidi(const MidiEvent& midiEvent)
 {
+       namespace mrh = m::recorderHandler;
+       namespace mr  = m::recorder;
+
        if (!armed)
                return;
 
-       /* Now all messages are turned into Channel-0 messages. Giada doesn't care about
-       holding MIDI channel information. Moreover, having all internal messages on
-       channel 0 is way easier. */
+       /* Now all messages are turned into Channel-0 messages. Giada doesn't care 
+       about holding MIDI channel information. Moreover, having all internal 
+       messages on channel 0 is way easier. */
 
        MidiEvent midiEventFlat(midiEvent);
        midiEventFlat.setChannel(0);
 
 #ifdef WITH_VST
 
-       while (true) {
-               if (pthread_mutex_trylock(&pluginHost::mutex_midi) != 0)
-                       continue;
-               gu_log("[MidiChannel::processMidi] msg=%X\n", midiEventFlat.getRaw());
-               addVstMidiEvent(midiEventFlat.getRaw(), 0);
-               pthread_mutex_unlock(&pluginHost::mutex_midi);
-               break;
-       }
+       pthread_mutex_lock(&pluginHost::mutex_midi);
+       addVstMidiEvent(midiEventFlat.getRaw(), 0);
+       pthread_mutex_unlock(&pluginHost::mutex_midi);
 
 #endif
 
-       if (recorder::canRec(this, clock::isRunning(), mixer::recording)) {
-               recorder::rec(index, G_ACTION_MIDI, clock::getCurrentFrame(), midiEventFlat.getRaw());
+       if (mr::isActive()) {
+               mrh::liveRec(index, midiEventFlat);
                hasActions = true;
        }
 }
@@ -242,4 +243,6 @@ void MidiChannel::receiveMidi(const MidiEvent& midiEvent)
 bool MidiChannel::canInputRec()
 {
        return false; // midi channels don't handle input audio
-}
\ No newline at end of file
+}
+
+}} // giada::m::
index 7185397bb025abade5d3f8ea5181f7063a3c3633..ee22e3fa64c5834955a99ddd59015b09010a65aa 100644 (file)
 #include "channel.h"
 
 
-class MidiMapConf;
-class Patch;
-
-
+namespace giada {
+namespace m 
+{
 class MidiChannel : public Channel
 {
 public:
@@ -46,9 +45,8 @@ public:
        MidiChannel(int bufferSize);
 
        void copy(const Channel* src, pthread_mutex_t* pluginMutex) override;
-       void parseEvents(giada::m::mixer::FrameEvents fe) override;
-       void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in, 
-               bool audible, bool running) override;
+       void parseEvents(mixer::FrameEvents fe) override;
+       void process(AudioBuffer& out, const AudioBuffer& in, bool audible, bool running) override;
        void start(int frame, bool doQuantize, int velocity) override;
        void kill(int localFrame) override;
        void empty() override;
@@ -56,16 +54,16 @@ public:
        void stop() override {};
        void rewindBySeq() override;
        void setMute(bool value) override;
-       void readPatch(const std::string& basePath, int i) override;
+       void setSolo(bool value) override;
+       void readPatch(const std::string& basePath, const patch::channel_t& pch) override;
        void writePatch(int i, bool isProject) override;
-       void receiveMidi(const giada::m::MidiEvent& midiEvent) override;
+       void receiveMidi(const MidiEvent& midiEvent) override;
        bool canInputRec() override;
 
        /* sendMidi
         * send Midi event to the outside world. */
 
-       void sendMidi(giada::m::recorder::action* a, int localFrame);
-       void sendMidi(uint32_t data);
+       void sendMidi(const Action* a, int localFrame);
 
 #ifdef WITH_VST
 
@@ -78,9 +76,11 @@ public:
 
 #endif
 
-       bool    midiOut;           // enable midi output
-       uint8_t midiOutChan;       // midi output channel
+       bool midiOut;      // enable midi output
+       int  midiOutChan;  // midi output channel
 };
 
+}} // giada::m::
+
 
 #endif
index 965d440a42177e256a4f2c7b8e98338f73c901ea..646c84db42edd7527d83009b037a78cde6977fbc 100644 (file)
@@ -2,8 +2,9 @@
 #include "pluginHost.h"
 #include "kernelMidi.h"
 #include "const.h"
+#include "action.h"
 #include "midiChannelProc.h"
-
+#include "mixerHandler.h"
 
 namespace giada {
 namespace m {
@@ -23,22 +24,6 @@ void onFirstBeat_(MidiChannel* ch)
                ch->sendMidiLstatus();
        }
 }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void parseAction_(MidiChannel* ch, const recorder::action* a, int localFrame)
-{
-       if (ch->isPlaying() && !ch->mute) {
-               if (ch->midiOut)
-                       kernelMidi::send(a->iValue | MIDI_CHANS[ch->midiOutChan]);
-#ifdef WITH_VST
-               ch->addVstMidiEvent(a->iValue, localFrame);
-#endif
-       }
-}
-
 }; // {anonymous}
 
 
@@ -51,21 +36,20 @@ void parseEvents(MidiChannel* ch, mixer::FrameEvents fe)
 {
        if (fe.onFirstBeat)
                onFirstBeat_(ch);
-       for (const recorder::action* action : fe.actions)
-               if (action->chan == ch->index && action->type == G_ACTION_MIDI)
-                       parseAction_(ch, action, fe.frameLocal);
+       for (const Action* action : fe.actions)
+               if (action->channel == ch->index)
+                       ch->sendMidi(action, fe.frameLocal);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void process(MidiChannel* ch, giada::m::AudioBuffer& out, 
-       const giada::m::AudioBuffer& in, bool audible)
+void process(MidiChannel* ch, AudioBuffer& out, const AudioBuffer& in, bool audible)
 {
-       #ifdef WITH_VST
-               pluginHost::processStack(ch->buffer, pluginHost::CHANNEL, ch);
-       #endif
+#ifdef WITH_VST
+       pluginHost::processStack(ch->buffer, pluginHost::CHANNEL, ch);
+#endif
 
        /* Process the plugin stack first, then quit if the channel is muted/soloed. 
        This way there's no risk of cutting midi event pairs such as note-on and 
@@ -149,6 +133,10 @@ void setMute(MidiChannel* ch, bool v)
                        ch->addVstMidiEvent(MIDI_ALL_NOTES_OFF, 0);
        #endif          
                }
+
+       // This is for processing playing_inaudible
+       ch->sendMidiLstatus();  
+
        ch->sendMidiLmute();
 }
 
@@ -156,8 +144,24 @@ void setMute(MidiChannel* ch, bool v)
 /* -------------------------------------------------------------------------- */
 
 
+void setSolo(MidiChannel* ch, bool v)
+{
+       ch->solo = v;
+       m::mh::updateSoloCount();
+
+       // This is for processing playing_inaudible
+       for (Channel* channel : mixer::channels)                
+               channel->sendMidiLstatus();
+
+       ch->sendMidiLsolo();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void stopBySeq(MidiChannel* ch)
 {
        kill(ch, 0);
 }
-}}};
\ No newline at end of file
+}}};
index ffd4929fa033a217f8ba4db90f3dee8419b6d31f..6abd14349b7ed9ee7aa452dbe7199f5d48fce9a8 100644 (file)
@@ -6,11 +6,11 @@
 #include "audioBuffer.h"
 
 
+namespace giada {
+namespace m 
+{
 class MidiChannel;
 
-
-namespace giada {
-namespace m {
 namespace midiChannelProc
 {
 /* parseEvents
@@ -19,8 +19,7 @@ Parses events gathered by Mixer::masterPlay(). */
 void parseEvents(MidiChannel* ch, mixer::FrameEvents ev);
 
 /**/
-void process(MidiChannel* ch, giada::m::AudioBuffer& out, 
-       const giada::m::AudioBuffer& in, bool audible);
+void process(MidiChannel* ch, AudioBuffer& out, const AudioBuffer& in, bool audible);
 
 /* kill
 Stops a channel abruptly. */
@@ -46,7 +45,8 @@ void rewindBySeq(MidiChannel* ch);
 Mutes/unmutes a channel. */
 
 void setMute(MidiChannel* ch, bool v);
+void setSolo(MidiChannel* ch, bool v);
 }}};
 
 
-#endif
\ No newline at end of file
+#endif
index 201a3855f7a097141382ab88ab297056645a0b4d..bb65bd825aa1e9e720a582631ba9831c9fbed47c 100644 (file)
@@ -131,7 +131,7 @@ void processChannels(const MidiEvent& midiEvent)
                        c::channel::toggleSolo(ch, false);
                }
                else if (pure == ch->midiInVolume) {
-                       float vf = midiEvent.getVelocity() / 127.0f;
+                       float vf = midiEvent.getVelocity() / 127.0f; // TODO: u::math::map
                        gu_log("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n",
                                ch->index, pure, midiEvent.getVelocity(), vf);
                        c::channel::setVolume(ch, vf, false);
@@ -139,7 +139,7 @@ void processChannels(const MidiEvent& midiEvent)
                else {
                        SampleChannel* sch = static_cast<SampleChannel*>(ch);
                        if (pure == sch->midiInPitch) {
-                               float vf = midiEvent.getVelocity() / (127/4.0f); // [0-127] ~> [0.0-4.0]
+                               float vf = midiEvent.getVelocity() / (127/4.0f); // [0-127] ~> [0.0-4.0] TODO: u::math::map
                                gu_log("  >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
                                        sch->index, pure, midiEvent.getVelocity(), vf);
                                c::channel::setPitch(sch, vf);
@@ -173,11 +173,11 @@ void processMaster(const MidiEvent& midiEvent)
 
        if      (pure == conf::midiInRewind) {
                gu_log("  >>> rewind (master) (pure=0x%X)\n", pure);
-               glue_rewindSeq(false);
+               c::transport::rewindSeq(false);
        }
        else if (pure == conf::midiInStartStop) {
                gu_log("  >>> startStop (master) (pure=0x%X)\n", pure);
-               glue_startStopSeq(false);
+               c::transport::startStopSeq(false);
        }
        else if (pure == conf::midiInActionRec) {
                gu_log("  >>> actionRec (master) (pure=0x%X)\n", pure);
@@ -189,7 +189,7 @@ void processMaster(const MidiEvent& midiEvent)
        }
        else if (pure == conf::midiInMetronome) {
                gu_log("  >>> metronome (master) (pure=0x%X)\n", pure);
-               glue_startStopMetronome(false);
+               c::transport::startStopMetronome(false);
        }
        else if (pure == conf::midiInVolumeIn) {
                float vf = midiEvent.getVelocity() / 127.0f;
index ac3aabc47b3a4b9f764c152fc0fa020c54393535..fdf63e08d83830930084dabb3c86987496c0c82c 100644 (file)
@@ -26,6 +26,7 @@
 
 
 #include <cassert>
+#include "const.h"
 #include "midiEvent.h"
 
 
@@ -85,7 +86,7 @@ void MidiEvent::setChannel(int c)
 
 void MidiEvent::setVelocity(int v)
 {
-       assert(v >= 0 && v < G_MAX_VELOCITY);
+       assert(v >= 0 && v <= G_MAX_VELOCITY);
        m_velocity = v;
 }
 
index 4c29e5241c32465a31375ff303f5225693eef2c5..3694b57704d23eb29a190aee2d4efdd1be406536 100644 (file)
@@ -39,8 +39,10 @@ class MidiEvent
 {
 public:
 
-       static const int NOTE_ON  = 0x90;
-       static const int NOTE_OFF = 0x80;
+       static const int NOTE_ON   = 0x90;
+       static const int NOTE_OFF  = 0x80;
+       static const int NOTE_KILL = 0x70;
+       static const int ENVELOPE  = 0xB0;
 
        MidiEvent();
        MidiEvent(uint32_t raw);
index 9c130088f07d010e6f6febc87316be85f6a990fb..0b04a8c16bd137411717a3ebf5243b71d78977ae 100644 (file)
@@ -96,7 +96,11 @@ void parse(message_t *message)
 {
        /* Remove '0x' part from the original string. */
 
-       string input = message->valueStr.replace(0, 2, "");
+       string input = message->valueStr;
+
+       size_t f = input.find("0x");                                    // check if "0x" is there
+       if (f!=std::string::npos)
+               input = message->valueStr.replace(f, 2, "");
 
        /* Then transform string value into the actual uint32_t value, by parsing
         * each char (i.e. nibble) in the original string. Substitute 'n' with
@@ -141,6 +145,7 @@ message_t waiting;
 message_t playing;
 message_t stopping;
 message_t stopped;
+message_t playing_inaudible;
 
 string midimapsPath;
 vector<string> maps;
@@ -221,6 +226,19 @@ void setDefault()
        stopped.valueStr  = "";
        stopped.offset    = -1;
        stopped.value     = 0;
+       playing_inaudible.channel   = 0;
+       playing_inaudible.valueStr  = "";
+       playing_inaudible.offset    = -1;
+       playing_inaudible.value     = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool isDefined(message_t msg)
+{
+       return (msg.offset!=-1);
 }
 
 
@@ -245,27 +263,17 @@ int read(const string &file)
   }
 
        if (!storager::setString(jRoot, MIDIMAP_KEY_BRAND, brand))   return MIDIMAP_UNREADABLE;
-  if (!storager::setString(jRoot, MIDIMAP_KEY_DEVICE, device)) return MIDIMAP_UNREADABLE;
+    if (!storager::setString(jRoot, MIDIMAP_KEY_DEVICE, device)) return MIDIMAP_UNREADABLE;
        if (!readInitCommands(jRoot)) return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &muteOn,   MIDIMAP_KEY_MUTE_ON))  return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &muteOff,  MIDIMAP_KEY_MUTE_OFF)) return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &soloOn,   MIDIMAP_KEY_SOLO_ON))  return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &soloOff,  MIDIMAP_KEY_SOLO_OFF)) return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &waiting,  MIDIMAP_KEY_WAITING))  return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &playing,  MIDIMAP_KEY_PLAYING))  return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &stopping, MIDIMAP_KEY_STOPPING)) return MIDIMAP_UNREADABLE;
-       if (!readCommand(jRoot, &stopped,  MIDIMAP_KEY_STOPPED))  return MIDIMAP_UNREADABLE;
-
-       /* parse messages */
-
-       parse(&muteOn);
-       parse(&muteOff);
-       parse(&soloOn);
-       parse(&soloOff);
-       parse(&waiting);
-       parse(&playing);
-       parse(&stopping);
-       parse(&stopped);
+       if (readCommand(jRoot, &muteOn,   MIDIMAP_KEY_MUTE_ON))  parse(&muteOn);
+       if (readCommand(jRoot, &muteOff,  MIDIMAP_KEY_MUTE_OFF)) parse(&muteOff);
+       if (readCommand(jRoot, &soloOn,   MIDIMAP_KEY_SOLO_ON))  parse(&soloOn);
+       if (readCommand(jRoot, &soloOff,  MIDIMAP_KEY_SOLO_OFF)) parse(&soloOff);
+       if (readCommand(jRoot, &waiting,  MIDIMAP_KEY_WAITING))  parse(&waiting);
+       if (readCommand(jRoot, &playing,  MIDIMAP_KEY_PLAYING))  parse(&playing);
+       if (readCommand(jRoot, &stopping, MIDIMAP_KEY_STOPPING)) parse(&stopping);
+       if (readCommand(jRoot, &stopped,  MIDIMAP_KEY_STOPPED))  parse(&stopped);
+       if (readCommand(jRoot, &playing_inaudible,  MIDIMAP_KEY_PLAYING_INAUDIBLE))  parse(&playing_inaudible);
 
        return MIDIMAP_READ_OK;
 }
index 0e73e7ded38be9ad24ddcc9ff7483cc40c402e40..6584d3518948afd5bc5084ea32842a2ce736fd0a 100644 (file)
@@ -39,8 +39,8 @@ namespace midimap
 {
 struct message_t
 {
-  int         channel;
-  std::string valueStr;
+    int         channel;
+    std::string valueStr;
        int         offset;
        uint32_t    value;
 };
@@ -56,6 +56,7 @@ extern message_t waiting;
 extern message_t playing;
 extern message_t stopping;
 extern message_t stopped;
+extern message_t playing_inaudible;
 
 /* midimapsPath
  * path of midimap files, different between OSes. */
@@ -74,10 +75,15 @@ Parse the midi maps folders and find the available maps. */
 void init();
 
 /* setDefault
-Set default values in case no maps are available/choosen. */
+Set default values in case no maps are available/chosen. */
 
 void setDefault();
 
+/* isDefined
+Check whether a specific message has been defined within midi map file.*/
+
+bool isDefined(message_t msg);
+
 /* read
 Read a midi map from file 'file'. */
 
index 05d64e03ae4fe0aef6abf0b127361de53198f2f7..2707572f49f400a5736aedc9eed37570e44b1754 100644 (file)
@@ -41,6 +41,7 @@
 #include "sampleChannel.h"
 #include "midiChannel.h"
 #include "audioBuffer.h"
+#include "action.h"
 #include "mixer.h"
 
 
@@ -352,6 +353,8 @@ int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize,
 
        prepareBuffers(out);
 
+       // TODO - move lock here
+
        for (unsigned j=0; j<bufferSize; j++) {
                processLineIn(in, j);   // TODO - can go outside this loop
 
@@ -378,6 +381,8 @@ int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize,
        
        renderIO(out, in);
 
+       // TODO - move unlock here
+
        /* Post processing. */
        for (unsigned j=0; j<bufferSize; j++) {
                finalizeOutput(out, j); 
index 3a1f81ec7518ad85e939f7e8df4281622d32ebb8..fea09bb9b7cf7f6d1ce097d3be3e715df8cfb90f 100644 (file)
 #include "../deps/rtaudio-mod/RtAudio.h"
 
 
+namespace giada {
+namespace m
+{
+struct Action;
 class Channel;
 
-
-namespace giada {
-namespace m {
 namespace mixer
 {
 struct FrameEvents
@@ -51,7 +52,7 @@ struct FrameEvents
        bool  onBar;
        bool  onFirstBeat;
        bool  quantoPassed;
-       std::vector<recorder::action*> actions;
+       std::vector<const Action*> actions;
 };
 
 extern std::vector<Channel*> channels;
index 66ecc810e90a58adc6770b6721227c7610292790..8601ed8d00a420a71e5b8641fe7ca19c29a1715e 100644 (file)
@@ -135,11 +135,8 @@ bool uniqueSamplePath(const SampleChannel* skip, const string& path)
 
 Channel* addChannel(ChannelType type)
 {
-       Channel* ch = nullptr;
-       channelManager::create(type, kernelAudio::getRealBufSize(), 
-               conf::inputMonitorDefaultOn, &ch);
-       if (ch == nullptr)
-               return nullptr;
+       Channel* ch = channelManager::create(type, kernelAudio::getRealBufSize(), 
+               conf::inputMonitorDefaultOn);
 
        while (true) {
                if (pthread_mutex_trylock(&mixer::mutex) != 0)
index b37a14c4c7969024d44d8241d38c2d4ffa13520c..895a1dcceefcd225553a4f30649546c3c8d1c390 100644 (file)
 #include "types.h"
 
 
-class Channel;
-class SampleChannel;
 
 
 namespace giada {
-namespace m {
+namespace m 
+{
+class Channel;
+class SampleChannel;
+
 namespace mh
 {
 /* addChannel
index 6691b6d3c03c0f3116d48ef3ec9e4ef4dccea07e..2add0b9f5e15d347f08fd2234e25021a90738fee 100644 (file)
 #include "../utils/log.h"
 #include "../utils/string.h"
 #include "../utils/ver.h"
+#include "../utils/math.h"
 #include "const.h"
 #include "types.h"
 #include "storager.h"
+#include "midiEvent.h"
 #include "conf.h"
 #include "mixer.h"
 #include "patch.h"
@@ -51,27 +53,28 @@ Internal sanity check. */
 
 void sanitize()
 {
-       bpm          = bpm < G_MIN_BPM || bpm > G_MAX_BPM ? G_DEFAULT_BPM : bpm;
-       bars         = bars <= 0 || bars > G_MAX_BARS ? G_DEFAULT_BARS : bars;
-       beats        = beats <= 0 || beats > G_MAX_BEATS ? G_DEFAULT_BEATS : beats;
-       quantize     = quantize < 0 || quantize > G_MAX_QUANTIZE ? G_DEFAULT_QUANTIZE : quantize;
-       masterVolIn  = masterVolIn < 0.0f || masterVolIn > 1.0f ? G_DEFAULT_VOL : masterVolIn;
-       masterVolOut = masterVolOut < 0.0f || masterVolOut > 1.0f ? G_DEFAULT_VOL : masterVolOut;
+       namespace um = u::math;
+
+       bpm          = um::bound(bpm, G_MIN_BPM, G_MAX_BPM, G_DEFAULT_BPM);
+       bars         = um::bound(bars, 1, G_MAX_BARS, G_DEFAULT_BARS);
+       beats        = um::bound(beats, 1, G_MAX_BEATS, G_DEFAULT_BEATS);
+       quantize     = um::bound(quantize, 0, G_MAX_QUANTIZE, G_DEFAULT_QUANTIZE);
+       masterVolIn  = um::bound(masterVolIn, 0.0f, 1.0f, G_DEFAULT_VOL);
+       masterVolOut = um::bound(masterVolOut, 0.0f, 1.0f, G_DEFAULT_VOL);
        samplerate   = samplerate <= 0 ? G_DEFAULT_SAMPLERATE : samplerate;
 
-       for (unsigned i=0; i<columns.size(); i++) {
-               column_t* col = &columns.at(i);
-               col->index = col->index < 0 ? 0 : col->index;
-               col->width = col->width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col->width;
+       for (column_t& col : columns) {
+               col.index = col.index < 0 ? 0 : col.index;
+               col.width = col.width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col.width;
        }
 
-       for (unsigned i=0; i<channels.size(); i++) {
-               channel_t* ch = &channels.at(i);
-               ch->size   = ch->size < G_GUI_CHANNEL_H_1 || ch->size > G_GUI_CHANNEL_H_4 ? G_GUI_CHANNEL_H_1 : ch->size;
-               ch->volume = ch->volume < 0.0f || ch->volume > 1.0f ? G_DEFAULT_VOL : ch->volume;
-               ch->pan    = ch->pan < 0.0f || ch->pan > 1.0f ? 1.0f : ch->pan;
-               ch->boost  = ch->boost < 1.0f ? G_DEFAULT_BOOST : ch->boost;
-               ch->pitch  = ch->pitch < 0.1f || ch->pitch > G_MAX_PITCH ? G_DEFAULT_PITCH : ch->pitch;
+       for (channel_t& ch : channels) {
+               ch.size        = um::bound(ch.size, G_GUI_CHANNEL_H_1, G_GUI_CHANNEL_H_4, G_GUI_CHANNEL_H_1);
+               ch.volume      = um::bound(ch.volume, 0.0f, 1.0f, G_DEFAULT_VOL);
+               ch.pan         = um::bound(ch.pan, 0.0f, 1.0f, 1.0f);
+               ch.boost       = um::bound(ch.boost, 1.0f, G_MAX_BOOST_DB, G_DEFAULT_BOOST);
+               ch.pitch       = um::bound(ch.pitch, 0.1f, G_MAX_PITCH, G_DEFAULT_PITCH);
+               ch.midiOutChan = um::bound(ch.midiOutChan, 0, G_MAX_MIDI_CHANS - 1, 0);
        }
 }
 
@@ -196,23 +199,50 @@ bool readActions(json_t* jContainer, channel_t* channel)
 {
        json_t* jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
        if (!storager::checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS))
-               return 0;
+               return false;
 
        size_t actionIndex;
        json_t* jAction;
        json_array_foreach(jActions, actionIndex, jAction) {
 
                if (!storager::checkObject(jAction, "")) // TODO pass actionIndex as string
-                       return 0;
+                       return false;
 
                action_t action;
-               if (!storager::setInt   (jAction, PATCH_KEY_ACTION_TYPE,    action.type)) return 0;
-               if (!storager::setInt   (jAction, PATCH_KEY_ACTION_FRAME,   action.frame)) return 0;
-               if (!storager::setFloat (jAction, PATCH_KEY_ACTION_F_VALUE, action.fValue)) return 0;
-               if (!storager::setUint32(jAction, PATCH_KEY_ACTION_I_VALUE, action.iValue)) return 0;
+
+               /* TODO - temporary code for backward compatibility with old actions. 
+               To be removed in 0.16.0. */
+               if (u::ver::isLess(versionMajor, versionMinor, versionPatch, 0, 15, 3)) {
+
+                       action.id = -1;
+                       action.channel = channel->index;
+                       if (!storager::setInt   (jAction, "frame", action.frame)) return 0;                     
+                       if (!storager::setUint32(jAction, "type",  action.event)) return 0;
+                       action.prev = -1;
+                       action.next = -1;
+
+                       if      (action.event == 0x01)   // KEY_PRESS
+                               action.event = MidiEvent(MidiEvent::NOTE_ON, 0, 0).getRaw();
+                       else if (action.event == 0x02)   // KEY_REL
+                               action.event = MidiEvent(MidiEvent::NOTE_OFF, 0, 0).getRaw();
+                       else if (action.event == 0x04)   // KEY_KILL
+                               action.event = MidiEvent(MidiEvent::NOTE_KILL, 0, 0).getRaw();
+                       else if (action.event == 0x20)   // VOLUME not supported, sorry :)
+                               continue;
+                       else if (action.event == 0x40)   // MIDI EVENT
+                               if (!storager::setUint32(jAction, "i_value", action.event)) return 0;
+               }
+               else {
+                       if (!storager::setInt   (jAction, G_PATCH_KEY_ACTION_ID,      action.id)) return 0;
+                       if (!storager::setInt   (jAction, G_PATCH_KEY_ACTION_CHANNEL, action.channel)) return 0;
+                       if (!storager::setInt   (jAction, G_PATCH_KEY_ACTION_FRAME,   action.frame)) return 0;
+                       if (!storager::setUint32(jAction, G_PATCH_KEY_ACTION_EVENT,   action.event)) return 0;
+                       if (!storager::setInt   (jAction, G_PATCH_KEY_ACTION_PREV,    action.prev)) return 0;
+                       if (!storager::setInt   (jAction, G_PATCH_KEY_ACTION_NEXT,    action.next)) return 0;
+               }
                channel->actions.push_back(action);
        }
-       return 1;
+       return true;
 }
 
 
@@ -269,8 +299,8 @@ bool readChannels(json_t* jContainer)
                if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR,        channel.inputMonitor)) return 0;
                if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, channel.midiInReadActions)) return 0;
                if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH,        channel.midiInPitch)) return 0;
-               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             channel.midiOut)) return 0;
-               if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        channel.midiOutChan)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT,             channel.midiOut)) return 0;
+               if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN,        channel.midiOutChan)) return 0;
                if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_ARMED,                channel.armed)) return 0;
 
                readActions(jChannel, &channel);
@@ -365,16 +395,17 @@ void writeColumns(json_t* jContainer, vector<column_t>* columns)
 /* -------------------------------------------------------------------------- */
 
 
-void writeActions(json_t*jContainer, vector<action_t>*actions)
+void writeActions(json_t* jContainer, vector<action_t>& actions)
 {
        json_t* jActions = json_array();
-       for (unsigned k=0; k<actions->size(); k++) {
-               json_t*  jAction = json_object();
-               action_t action  = actions->at(k);
-               json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE,    json_integer(action.type));
-               json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME,   json_integer(action.frame));
-               json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue));
-               json_object_set_new(jAction, PATCH_KEY_ACTION_I_VALUE, json_integer(action.iValue));
+       for (action_t action : actions) {
+               json_t* jAction = json_object();
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_ID,      json_integer(action.id));
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_CHANNEL, json_integer(action.channel));
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_FRAME,   json_integer(action.frame));
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_EVENT,   json_integer(action.event));
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_PREV,    json_integer(action.prev));
+               json_object_set_new(jAction, G_PATCH_KEY_ACTION_NEXT,    json_integer(action.next));
                json_array_append_new(jActions, jAction);
        }
        json_object_set_new(jContainer, PATCH_KEY_CHANNEL_ACTIONS, jActions);
@@ -452,7 +483,7 @@ void writeChannels(json_t* jContainer, vector<channel_t>* channels)
                json_object_set_new(jChannel, PATCH_KEY_CHANNEL_ARMED,                json_boolean(channel.armed));
                json_array_append_new(jChannels, jChannel);
 
-               writeActions(jChannel, &channel.actions);
+               writeActions(jChannel, channel.actions);
 
 #ifdef WITH_VST
 
index 77d48d7a28ddaed8b80c02b7541d7821c0259564..afc51801552360f684200a972576fca426fe0144 100644 (file)
@@ -40,10 +40,12 @@ namespace patch
 {
 struct action_t
 {
-       int      type;
+       int      id;
+       int      channel;
        int      frame;
-       float    fValue;
-       uint32_t iValue;
+       uint32_t event;
+       int      prev;
+       int      next;
 };
 
 #ifdef WITH_VST
@@ -95,8 +97,8 @@ struct channel_t
        uint32_t    midiInReadActions;
        uint32_t    midiInPitch;
        // midi channel
-       uint32_t    midiOut;
-       uint32_t    midiOutChan;
+       int         midiOut;   // TODO - should be bool
+       int         midiOutChan;
 
        std::vector<action_t> actions;
 
index b3c4e809969027d7c019191e2d1d7df5fd8233d1..2af8fae2790bae19b26dc69fcf7efbd952709b8d 100644 (file)
 
 
 using std::string;
-using namespace giada::u;
 
 
+namespace giada {
+namespace m 
+{
 int Plugin::idGenerator = 1;
 
 
@@ -49,9 +51,9 @@ int Plugin::idGenerator = 1;
 Plugin::Plugin(juce::AudioPluginInstance* plugin, double samplerate,
        int buffersize)
        : ui    (nullptr),
-               plugin(plugin),
-               id    (idGenerator++),
-               bypass(false)
+         plugin(plugin),
+         id    (idGenerator++),
+         bypass(false)
 {
        using namespace juce;
 
@@ -287,4 +289,7 @@ void Plugin::closeEditor()
        ui = nullptr;
 }
 
+}} // giada::m::
+
+
 #endif
index 62633c482018994f4b199c751b20f8ef929b38cf..61202b6144e6dbf4e46f51a1d2f0f39de0f1bbe6 100644 (file)
@@ -34,6 +34,9 @@
 #include "../deps/juce-config.h"
 
 
+namespace giada {
+namespace m 
+{
 class Plugin
 {
 private:
@@ -104,6 +107,8 @@ public:
        std::vector<uint32_t> midiInParams;
 };
 
+}} // giada::m::
+
 #endif
 
 #endif // #ifdef WITH_VST
index 6ba04653398dd768b2ee2376de1cbaa85622f98b..2e84fe8a7f752619b8c7d58433ca4a2732c8ef13 100644 (file)
@@ -184,7 +184,7 @@ int scanDirs(const string& dirs, const std::function<void(float)>& cb)
                searchPath.add(juce::File(dir));
 
        juce::PluginDirectoryScanner scanner(knownPluginList, format, searchPath, 
-               true, juce::File::nonexistent); // true: recursive
+               true, juce::File()); // true: recursive
 
        juce::String name;
        while (scanner.scanNextFile(false, name)) {
index dcb749fffc7651f6f8d29d8be5747c98063260b0..aff17a9e9da28a82632d06957cf0c33d4ca61c20 100644 (file)
 #include "audioBuffer.h"
 
 
-class Plugin;
-class Channel;
 
 
 namespace giada {
-namespace m {
+namespace m 
+{
+class Plugin;
+class Channel;
+
 namespace pluginHost
 {
 enum stackType
index a54524d04e30b73f01d3506580bed9c436b96070..0f7803bfbc8839499f195e89e4a2c5ce6fd58989 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <memory>
+#include <algorithm>
 #include <cassert>
-#include <cmath>
 #include "../utils/log.h"
-#include "const.h"
-#include "sampleChannel.h"
+#include "action.h"
+#include "channel.h"
 #include "recorder.h"
 
 
+using std::map;
 using std::vector;
 
 
@@ -42,460 +44,224 @@ namespace recorder
 {
 namespace
 {
-/* Composite
-A group of two actions (keypress+keyrel, muteon+muteoff) used during the overdub 
-process. */
+/* actions
+The big map of actions {frame : actions[]}. This belongs to Recorder, but it
+is often parsed by Mixer. So every "write" action performed on it (add, 
+remove, ...) must be guarded by a lock on the mixerMutex. Until a proper
+lock-free solution will be implemented. */
 
-Composite cmp;
+ActionMap actions;
 
-
-/* -------------------------------------------------------------------------- */
-
-
-/* fixOverdubTruncation
-Fixes underlying action truncation when overdubbing over a longer action. I.e.:
-       Original:    |#############|
-       Overdub:     ---|#######|---
-       fix:         |#||#######|--- */
-
-void fixOverdubTruncation(const Composite& comp, pthread_mutex_t* mixerMutex)
-{
-       action* next = nullptr;
-       int res = getNextAction(comp.a2.chan, comp.a1.type | comp.a2.type, comp.a2.frame,
-               &next);
-       if (res != 1 || next->type != comp.a2.type)
-               return;
-       gu_log("[recorder::fixOverdubTruncation] add truncation at frame %d, type=%d\n",
-               next->frame, next->type);
-       deleteAction(next->chan, next->frame, next->type, false, mixerMutex);
-}
-
-}; // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-vector<int> frames;
-vector<vector<action*>> global;
-vector<action*> actions;     // used internally
-
-bool active = false;
-bool sortedActions = false;
+pthread_mutex_t* mixerMutex = nullptr;
+bool             active     = false;
+int              actionId   = 0;
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void init()
+void lock_(std::function<void()> f)
 {
-       active = false;
-       sortedActions = false;
-       clearAll();
+       assert(mixerMutex != nullptr);
+       pthread_mutex_lock(mixerMutex);
+       f();
+       pthread_mutex_unlock(mixerMutex);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
+/* optimize
+Removes frames without actions. */
 
-bool canRec(Channel* ch, bool clockRunning, bool mixerRecording)
+void optimize_(ActionMap& map)
 {
-       /* Can record on a channel if:
-               - recorder is on
-               - mixer is running
-               - mixer is not recording a take somewhere
-               - channel is MIDI or SAMPLE type with data in it  */
-       return active && clockRunning && !mixerRecording && 
-              (ch->type == ChannelType::MIDI || (ch->type == ChannelType::SAMPLE && ch->hasData()));
+       for (auto it = map.cbegin(); it != map.cend();)
+               it->second.size() == 0 ? it = map.erase(it) : ++it;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void rec(int index, int type, int frame, uint32_t iValue, float fValue)
+void removeIf_(std::function<bool(const Action*)> f)
 {
-       /* allocating the action */
-
-       action* a = (action*) malloc(sizeof(action)); /* TODO - AAARRRGGHHHHHH!!!! */
-       a->chan   = index;
-       a->type   = type;
-       a->frame  = frame;
-       a->iValue = iValue;
-       a->fValue = fValue;
-
-       /* check if the frame exists in the stack. If it exists, we don't extend
-        * the stack, but we add (or push) a new action to it. */
-
-       int frameToExpand = frames.size();
-       for (int i=0; i<frameToExpand; i++)
-               if (frames.at(i) == frame) {
-                       frameToExpand = i;
-                       break;
-               }
-
-       /* espansione dello stack frames nel caso l'azione ricada in frame
-        * non precedentemente memorizzati (frameToExpand == frames.size()).
-        * Espandere frames è facile, basta aggiungere un frame in coda.
-        * Espandere global è più complesso: bisogna prima allocare una
-        * cella in global (per renderlo parallelo a frames) e poi
-        * inizializzare il suo sub-stack (di action). */
-
-       if (frameToExpand == (int) frames.size()) {
-               frames.push_back(frame);
-               global.push_back(actions);               // array of actions added
-               global.at(global.size()-1).push_back(a); // action added
-       }
-       else {
-
-               /* no duplicates, please */
-
-               for (unsigned t=0; t<global.at(frameToExpand).size(); t++) {
-                       action* ac = global.at(frameToExpand).at(t);
-                       if (ac->chan   == index  &&
-                                       ac->type   == type   &&
-                                       ac->frame  == frame  &&
-                                       ac->iValue == iValue &&
-                                       ac->fValue == fValue)
-                               return;
+       ActionMap temp = actions;
+
+       /*
+       for (auto& kv : temp) {
+               vector<Action*>& as = kv.second;
+               as.erase(std::remove_if(as.begin(), as.end(), f), as.end());
+       }*/
+       for (auto& kv : temp) {
+               auto i = std::begin(kv.second);
+               while (i != std::end(kv.second)) {
+                       if (f(*i)) {
+                               delete *i;
+                               i = kv.second.erase(i);
+                       }
+                       else
+                               ++i;
                }
-
-               global.at(frameToExpand).push_back(a);          // expand array
        }
+       optimize_(temp);
 
-       sortedActions = false;
-
-       gu_log("[recorder::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();
+       lock_([&](){ actions = std::move(temp); });
 }
+} // {anonymous}
 
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 
-void clearChan(int index)
+void init(pthread_mutex_t* m)
 {
-       gu_log("[recorder::clearChan] clearing chan %d...\n", index);
-
-       for (unsigned i=0; i<global.size(); i++) {      // for each frame i
-               unsigned j=0;
-               while (true) {
-                       if (j == global.at(i).size()) break;      // for each action j of frame i
-                       action* a = global.at(i).at(j);
-                       if (a->chan == index)   {
-                               free(a);
-                               global.at(i).erase(global.at(i).begin() + j);
-                       }
-                       else
-                               j++;
-               }
-       }
-       optimize();
-       //print();
+       mixerMutex = m;
+       active     = false;
+       actionId   = 0;
+       clearAll();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void clearAction(int index, char act)
+void debug()
 {
-       gu_log("[recorder::clearAction] clearing action %d from chan %d...\n", act, index);
-       for (unsigned i=0; i<global.size(); i++) {                                              // for each frame i
-               unsigned j=0;
-               while (true) {                                   // for each action j of frame i
-                       if (j == global.at(i).size())
-                               break;
-                       action* a = global.at(i).at(j);
-                       if (a->chan == index && (act & a->type) == a->type)     { // bitmask
-                               free(a);
-                               global.at(i).erase(global.at(i).begin() + j);
-                       }
-                       else
-                               j++;
+       int total = 0;
+       puts("-------------");
+       for (auto& kv : actions) {
+               printf("frame: %d\n", kv.first);
+               for (const Action* a : kv.second) {
+                       total++;
+                       printf(" this=%p - id=%d, frame=%d, channel=%d, value=0x%X, prev=%p, next=%p\n", 
+                               (void*) a, a->id, a->frame, a->channel, a->event.getRaw(), (void*) a->prev, (void*) a->next);   
                }
        }
-       optimize();
-       //print();
+       printf("TOTAL: %d\n", total);
+       puts("-------------");
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void deleteAction(int chan, int frame, char type, bool checkValues,
-       pthread_mutex_t* mixerMutex, uint32_t iValue, float fValue)
+void clearAll()
 {
-       /* find the frame 'frame' */
-
-       bool found = false;
-       for (unsigned i=0; i<frames.size() && !found; i++) {
-
-               if (frames.at(i) != frame)
-                       continue;
-
-                       /* find the action in frame i */
-
-               for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action* a = global.at(i).at(j);
-
-                       /* action comparison logic */
-
-                       bool doit = (a->chan == chan && a->type == (type & a->type));
-                       if (checkValues)
-                               doit &= (a->iValue == iValue && a->fValue == fValue);
-
-                       if (!doit)
-                               continue;
-
-                       while (true) {
-                               if (pthread_mutex_trylock(mixerMutex)) {
-                                       free(a);
-                                       global.at(i).erase(global.at(i).begin() + j);
-                                       pthread_mutex_unlock(mixerMutex);
-                                       found = true;
-                                       break;
-                               }
-                               else
-                                       gu_log("[recorder::deleteAction] waiting for mutex...\n");
-                       }
-               }
-       }
-       if (found) {
-               optimize();
-               gu_log("[recorder::deleteAction] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
-                       type, frame, chan, iValue, iValue, fValue);
-       }
-       else
-               gu_log("[recorder::deleteAction] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n",
-                       type, frame, chan, iValue, iValue, fValue);
+       removeIf_([=](const Action* a) { return true; }); // TODO optimize this
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void deleteActions(int chan, int frame_a, int frame_b, char type,
-       pthread_mutex_t* mixerMutex)
+void clearChannel(int channel)
 {
-       sortActions();
-       vector<int> dels;
-
-       for (unsigned i=0; i<frames.size(); i++)
-               if (frames.at(i) > frame_a && frames.at(i) < frame_b)
-                       dels.push_back(frames.at(i));
-
-       for (unsigned i=0; i<dels.size(); i++)
-               deleteAction(chan, dels.at(i), type, false, mixerMutex); // false == don't check values
+       removeIf_([=](const Action* a) { return a->channel == channel; });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void clearAll()
+void clearActions(int channel, int type)
 {
-       while (global.size() > 0) {
-               for (unsigned i=0; i<global.size(); i++) {
-                       for (unsigned k=0; k<global.at(i).size(); k++)
-                               free(global.at(i).at(k));                                                                       // free action
-                       global.at(i).clear();                                                                                           // free action container
-                       global.erase(global.begin() + i);
-               }
-       }
-       global.clear();
-       frames.clear();
+       removeIf_([=](const Action* a)
+       { 
+               return a->channel == channel && a->event.getStatus() == type;
+       });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void optimize()
+void deleteAction(const Action* target)
 {
-       /* do something until the i frame is empty. */
-
-       unsigned i = 0;
-       while (true) {
-               if (i == global.size()) return;
-               if (global.at(i).size() == 0) {
-                       global.erase(global.begin() + i);
-                       frames.erase(frames.begin() + i);
-               }
-               else
-                       i++;
-       }
-
-       sortActions();
+       removeIf_([=](const Action* a) { return a == target; });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void sortActions()
+void updateKeyFrames(std::function<Frame(Frame old)> f)
 {
-       if (sortedActions)
-               return;
-       for (unsigned i=0; i<frames.size(); i++)
-               for (unsigned j=0; j<frames.size(); j++)
-                       if (frames.at(j) > frames.at(i)) {
-                               std::swap(frames.at(j), frames.at(i));
-                               std::swap(global.at(j), global.at(i));
-                       }
-       sortedActions = true;
-       //print();
+       /* This stuff must be performed in a lock, because we are moving the vector
+       of actions from the real ActionMap to the temporary one. */
+       
+       ActionMap temp;
+
+       lock_([&]()
+       { 
+               for (auto& kv : actions) {
+                       Frame frame = f(kv.first);
+                       temp[frame] = std::move(kv.second);  // Move std::vector<Action*>
+                       for (const Action* action : temp[frame])
+                               const_cast<Action*>(action)->frame = frame;
+                       gu_log("[recorder::updateKeyFrames] %d -> %d\n", kv.first, frame);
+               }
+               actions = std::move(temp); 
+       });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void updateBpm(float oldval, float newval, int oldquanto)
+void updateEvent(const Action* a, MidiEvent e)
 {
-       for (unsigned i=0; i<frames.size(); i++) {
-
-               float frame  = ((float) frames.at(i)/newval) * oldval;
-               frames.at(i) = (int) frame;
-
-               /* the division up here cannot be precise. A new frame can be 44099
-                * and the quantizer set to 44100. That would mean two recs completely
-                * useless. So we compute a reject value ('scarto'): if it's lower
-                * than 6 frames the new frame is collapsed with a quantized frame. */
-               /** XXX - maybe 6 frames are too low */
-
-               if (frames.at(i) != 0) {
-                       int scarto = oldquanto % frames.at(i);
-                       if (scarto > 0 && scarto <= 6)
-                               frames.at(i) = frames.at(i) + scarto;
-               }
-       }
-
-       /* update structs */
-
-       for (unsigned i=0; i<frames.size(); i++) {
-               for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action* a = global.at(i).at(j);
-                       a->frame = frames.at(i);
-               }
-       }
-
-       //print();
+       assert(a != nullptr);
+       lock_([&] { const_cast<Action*>(a)->event = e; });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void updateSamplerate(int systemRate, int patchRate)
+void updateSiblings(const Action* a, const Action* prev, const Action* next)
 {
-       /* diff ratio: systemRate / patchRate
-        * e.g.  44100 / 96000 = 0.4... */
-
-       if (systemRate == patchRate)
-               return;
-
-       gu_log("[recorder::updateSamplerate] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate);
-
-       float ratio = systemRate / (float) patchRate;
-       for (unsigned i=0; i<frames.size(); i++) {
-
-               gu_log("[recorder::updateSamplerate]    oldFrame = %d", frames.at(i));
-
-               float newFrame = frames.at(i);
-               newFrame = floorf(newFrame * ratio);
-
-               frames.at(i) = (int) newFrame;
-
-               gu_log(", newFrame = %d\n", frames.at(i));
-       }
-
-       /* update structs */
-
-       for (unsigned i=0; i<frames.size(); i++) {
-               for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action* a = global.at(i).at(j);
-                       a->frame = frames.at(i);
-               }
-       }
+       assert(a != nullptr);
+       lock_([&] 
+       { 
+               const_cast<Action*>(a)->prev = prev;
+               const_cast<Action*>(a)->next = next;
+               if (prev != nullptr) const_cast<Action*>(prev)->next = a;               
+               if (next != nullptr) const_cast<Action*>(next)->prev = a;       
+       });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void expand(int old_fpb, int new_fpb)
+void updateActionMap(ActionMap&& am)
 {
-       /* this algorithm requires multiple passages if we expand from e.g. 2
-        * to 16 beats, precisely 16 / 2 - 1 = 7 times (-1 is the first group,
-        * which exists yet). If we expand by a non-multiple, the result is zero,
-        * due to float->int implicit cast */
-
-       unsigned pass = (int) (new_fpb / old_fpb) - 1;
-       if (pass == 0) pass = 1;
-
-       unsigned init_fs = frames.size();
-
-       for (unsigned z=1; z<=pass; z++) {
-               for (unsigned i=0; i<init_fs; i++) {
-                       unsigned newframe = frames.at(i) + (old_fpb*z);
-                       frames.push_back(newframe);
-                       global.push_back(actions);
-                       for (unsigned k=0; k<global.at(i).size(); k++) {
-                               action* a = global.at(i).at(k);
-                               rec(a->chan, a->type, newframe, a->iValue, a->fValue);
-                       }
-               }
-       }
-       gu_log("[recorder::expand] expanded recs\n");
-       //print();
+       lock_([&](){ actions = am; });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void shrink(int new_fpb)
+void updateActionId(int id)
 {
-       /* easier than expand(): here we delete eveything beyond old_framesPerBars. */
-
-       unsigned i=0;
-       while (true) {
-               if (i == frames.size()) break;
-
-               if (frames.at(i) >= new_fpb) {
-                       for (unsigned k=0; k<global.at(i).size(); k++)
-                               free(global.at(i).at(k));                     // free action
-                       global.at(i).clear();                                                           // free action container
-                       global.erase(global.begin() + i);   // shrink global
-                       frames.erase(frames.begin() + i);   // shrink frames
-               }
-               else
-                       i++;
-       }
-       optimize();
-       gu_log("[recorder::shrink] shrinked recs\n");
-       //print();
+       if (actionId <= id)  // Never decrease it
+               actionId = id;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-bool hasActions(int chanIndex, int type)
+bool hasActions(int channel, int type)
 {
-       if (global.size() == 0)
-               return false;
-       for (unsigned i=0; i<global.size(); i++) {
-               for (unsigned j=0; j<global.at(i).size(); j++) {
-                       if (global.at(i).at(j)->chan == chanIndex)
-                               if (type == -1 || global.at(i).at(j)->type == type)
-                                       return true;
-               }
-       }
+       for (auto& kv : actions)
+               for (const Action* action : kv.second)
+                       if (action->channel == channel && (type == 0 || type == action->event.getStatus()))
+                               return true;
        return false;
 }
 
@@ -503,172 +269,109 @@ bool hasActions(int chanIndex, int type)
 /* -------------------------------------------------------------------------- */
 
 
-int getNextAction(int chan, char type, int fromFrame, action** out, 
-       uint32_t iValue, uint32_t mask)
-{
-       sortActions();  // mandatory
-
-       /* Increase 'i' until it reaches 'fromFrame'. That's the point where to start
-       to look for the next action. */
-
-       unsigned i = 0;
-       while (i < frames.size() && frames.at(i) <= fromFrame) i++;
+bool isActive() { return active; }
+void enable()   { active = true; }
+void disable()  { active = false; }
 
-       /* No other actions past 'fromFrame': there are no more actions to look for.
-       Return -1. */
 
-       if (i == frames.size())
-               return -1;
-
-       for (; i<global.size(); i++) {
+/* -------------------------------------------------------------------------- */
 
-               for (unsigned j=0; j<global.at(i).size(); j++) {
 
-                       action* a = global.at(i).at(j);
+const Action* makeAction(int id, int channel, Frame frame, MidiEvent e)
+{
+       return new Action{ id, channel, frame, e, -1, -1, nullptr, nullptr };
+}
 
-                       /* If the requested channel and type don't match, continue. */
 
-                       if (a->chan != chan || (type & a->type) != a->type) 
-                               continue;
+/* -------------------------------------------------------------------------- */
 
-                       /* If no iValue has been specified (iValue == 0), then the next action has 
-                       been found, return it. Otherwise, make sure the iValue matches the 
-                       action's iValue, according to the mask provided. */
 
-                       if (iValue == 0 || (iValue != 0 && (a->iValue | mask) == (iValue | mask))) {
-                               *out = global.at(i).at(j);
-                               return 1;
-                       }
-               }
-       }
-       return -2;   // no 'type' actions found
+const Action* rec(int channel, Frame frame, MidiEvent event)
+{
+       /* If key frame doesn't exist yet, the [] operator in std::map is smart 
+       enough to insert a new item first. No plug-in data for now. */
+
+       lock_([&]
+       { 
+               actions[frame].push_back(makeAction(actionId++, channel, frame, event));
+       });
+       return actions[frame].back();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-int getAction(int chan, char action, int frame, struct action** out)
+void rec(const std::vector<const Action*>& as)
 {
-       for (unsigned i=0; i<global.size(); i++)
-               for (unsigned j=0; j<global.at(i).size(); j++)
-                       if (frame  == global.at(i).at(j)->frame &&
-                                       action == global.at(i).at(j)->type &&
-                                       chan   == global.at(i).at(j)->chan)
-                       {
-                               *out = global.at(i).at(j);
-                               return 1;
-                       }
-       return 0;
+       ActionMap temp = actions;
+
+       for (const Action* a : as) {
+               const_cast<Action*>(a)->id = actionId++;
+               temp[a->frame].push_back(a); // Memory is already allocated by recorderHandler
+       }
+
+       lock_([&](){ actions = std::move(temp); });
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void startOverdub(int index, char actionMask, int frame, unsigned bufferSize)
+vector<const Action*> getActionsOnFrame(Frame frame)
 {
-       /* prepare the composite struct */
-
-       cmp.a1.type  = G_ACTION_KEYPRESS;
-       cmp.a2.type  = G_ACTION_KEYREL;
-       cmp.a1.chan  = index;
-       cmp.a2.chan  = index;
-       cmp.a1.frame = frame;
-       // cmp.a2.frame doesn't exist yet
-
-       /* avoid underlying action truncation: if action2.type == nextAction:
-        * you are in the middle of a composite action, truncation needed */
-
-       rec(index, cmp.a1.type, frame);
-
-       action* act = nullptr;
-       int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act);
-       if (res == 1) {
-               if (act->type == cmp.a2.type) {
-                       int truncFrame = cmp.a1.frame - bufferSize;
-                       if (truncFrame < 0)
-                               truncFrame = 0;
-                       gu_log("[recorder::startOverdub] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type);
-                       rec(index, cmp.a2.type, truncFrame);
-               }
-       }
+       return actions.count(frame) ? actions[frame] : vector<const Action*>();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t* mixerMutex)
+const Action* getClosestAction(int channel, Frame f, int type)
 {
-       cmp.a2.frame  = currentFrame;
-       bool ringLoop = false;
-       bool nullLoop = false;
-
-       /* Check for ring loops or null loops. Ring loop: a composite action with
-       key_press at frame N and key_release at frame M, with M <= N.
-       Null loop: a composite action that begins and ends on the very same frame,
-       i.e. with 0 size. Very unlikely.
-       If ring loop: record the last action at the end of the sequencer (that
-       is 'totalFrames').
-       If null loop: remove previous action and do nothing. Also make sure to avoid
-       underlying action truncation, if the null loop occurs inside a composite
-       action. */
-
-       if (cmp.a2.frame < cmp.a1.frame) {  // ring loop
-               ringLoop = true;
-               gu_log("[recorder::stopOverdub] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
-               rec(cmp.a2.chan, cmp.a2.type, totalFrames);
-       }
-       else
-       if (cmp.a2.frame == cmp.a1.frame) { // null loop
-               nullLoop = true;
-               gu_log("[recorder::stopOverdub] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame);
-               deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false, mixerMutex); // false == don't check values
-               fixOverdubTruncation(cmp, mixerMutex);
-       }
-
-       if (nullLoop)
-               return;
+       const Action* out = nullptr;
+       forEachAction([&](const Action* a)
+       {
+               if (a->event.getStatus() != type || a->channel != channel)
+                       return;
+               if (out == nullptr || (a->frame <= f && a->frame > out->frame))
+                       out = a;
+       });
+       return out;
+}
 
-       /* Remove any nested action between keypress----keyrel. */
 
-       deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type, mixerMutex);
-       deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type, mixerMutex);
+/* -------------------------------------------------------------------------- */
 
-       if (ringLoop)
-               return;
 
-       /* Record second part of the composite action. Also make sure to avoid
-       underlying action truncation, if keyrel happens inside a composite action. */
+ActionMap getActionMap() { return actions; }
 
-       rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
-       fixOverdubTruncation(cmp, mixerMutex);
-}
+int getLatestActionId() { return actionId; }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-vector<action*> getActionsOnFrame(int frame)
+vector<const Action*> getActionsOnChannel(int channel)
 {
-       for (size_t i=0; i<frames.size(); i++) {
-               if (recorder::frames.at(i) != frame)
-                       continue;
-               return global.at(i);
-       }
-       return vector<action*>();
+       vector<const Action*> out;
+       forEachAction([&](const Action* a)
+       {
+               if (a->channel == channel)
+                       out.push_back(a);
+       });
+       return out;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void forEachAction(std::function<void(const action*)> f)
+void forEachAction(std::function<void(const Action*)> f)
 {
-
-       for (const vector<action*> actions : recorder::global)
-               for (const action* action : actions)
+       for (auto& kv : actions)
+               for (const Action* action : kv.second)
                        f(action);
 }
+
 }}}; // giada::m::recorder::
index d62017b8c6ce78e0bfbc26314c4a6e5e51808e5c..dfb6b0aa7b9fa41a3d4d80364e415c2aa1451f90 100644 (file)
 #define G_RECORDER_H
 
 
-#include <cstdint>
+#include <pthread.h>
+#include <map>
 #include <vector>
 #include <functional>
-#include <pthread.h>
-
-
-class Channel;
+#include "types.h"
+#include "midiEvent.h"
 
 
 namespace giada {
-namespace m {
-namespace recorder
+namespace m 
 {
-/* 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 Action;
 
-struct action
+namespace recorder
 {
-       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
-};
-
-/* Composite
-A group of two actions (keypress+keyrel, muteon+muteoff). */
+using ActionMap = std::map<Frame, std::vector<const Action*>>;
 
-struct Composite
-{
-       action a1;
-       action a2;
-};
+void debug();
+/* init
+Initializes the recorder: everything starts from here. */
 
-/* frames
-Frame counter sentinel. It tells which frames contain actions. E.g.:
-  frames[0] = 155   // some actions on frame 155
-  frames[1] = 2048  // some actions on frame 2048
-It always matches 'global''s size: frames.size() == global.size() */
+void init(pthread_mutex_t* mixerMutex);
 
-extern std::vector<int> frames;
+/* clearAll
+Deletes all recorded actions. */
 
-/* global
-Contains the actual actions. E.g.:
-  global[0] = <actions>
-  global[1] = <actions> */
+void clearAll();
 
-extern std::vector<std::vector<action*>> global;
-/* TODO - this frames vs global madness must be replaced with a map:
-std::map<int, vector<actions>> */
+/* clearChannel
+Clears all actions from a channel. */
 
-extern bool active;
-extern bool sortedActions;   // are actions sorted via sortActions()?
+void clearChannel(int channel);
 
-/* init
- * everything starts from here. */
+/* clearActions
+Clears the actions by type from a channel. */
 
-void init();
+void clearActions(int channel, int type);
 
-/* hasActions
-Checks if the channel has at least one action recorded. Used after an
-action deletion. Type != -1: check if channel has actions of type 'type'.*/
-
-bool hasActions(int chanIndex, int type=-1);
-
-/* canRec
- * can a channel rec an action? Call this one BEFORE rec(). */
+/* deleteAction
+Deletes a specific action. */
 
-bool canRec(Channel* ch, bool clockRunning, bool mixerRecording);
+void deleteAction(const Action* a);
 
-/* rec
- * record an action. */
+/* updateKeyFrames
+Update all the key frames in the internal map of actions, according to a lambda 
+function 'f'. */
 
-void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f);
+void updateKeyFrames(std::function<Frame(Frame old)> f);
 
-/* clearChan
- * clear all actions from a channel. */
+/* updateActionMap
+Replaces the current map of actions with a new one. Warning: 'am' will be moved
+as a replacement (no copy). */
 
-void clearChan(int chan);
+void updateActionMap(ActionMap&& am);
 
-/* clearAction
- * clear the 'action' action type from a channel. */
+/* updateEvent
+Changes the event in action 'a'. */
 
-void clearAction(int chan, char action);
+void updateEvent(const Action* a, MidiEvent e);
 
-/* deleteAction
- * delete ONE action. Useful in the action editor. 'type' can be a mask. */
+/* updateSiblings
+Changes previous and next actions in action 'a'. Mostly used for chained actions
+such as envelopes. */
 
-void deleteAction(int chan, int frame, char type, bool checkValues,
-  pthread_mutex_t* mixerMutex, uint32_t iValue=0, float fValue=0.0);
+void updateSiblings(const Action* a, const Action* prev, const Action* next);
 
-/* deleteActions
-Deletes A RANGE of actions from frame_a to frame_b in channel 'chan' of type
-'type' (can be a bitmask). Exclusive range (frame_a, frame_b). */
+void updateActionId(int id);
 
-void deleteActions(int chan, int frame_a, int frame_b, char type,
-  pthread_mutex_t* mixerMutex);
+/* hasActions
+Checks if the channel has at least one action recorded. */
 
-/* clearAll
- * delete everything. */
+bool hasActions(int channel, int type=0);
 
-void clearAll();
+/* isActive
+Is recorder recording something? */
 
-/* optimize
- * clear frames without actions. */
+bool isActive();
 
-void optimize();
+void enable();
+void disable();
 
-/* sortActions
- * sorts actions by frame, asc mode. */
+const Action* makeAction(int id, int channel, Frame frame, MidiEvent e);
 
-void sortActions();
+/* rec (1)
+Records an action and returns it. */
 
-/* updateBpm
- * reassign frames by calculating the new bpm value. */
+const Action* rec(int channel, Frame frame, MidiEvent e);
 
-void updateBpm(float oldval, float newval, int oldquanto);
+/* rec (2)
+Transfer a vector of actions into the current ActionMap. This is called by 
+recordHandler when a live session is over and consolidation is required. */
 
-/* updateSamplerate
- * reassign frames taking in account the samplerate. If f_system ==
- * f_patch nothing changes, otherwise the conversion is mandatory. */
+void rec(const std::vector<const Action*>& actions);
 
-void updateSamplerate(int systemRate, int patchRate);
+/* forEachAction
+Applies a read-only callback on each action recorded. NEVER do anything inside 
+the callback that might alter the ActionMap. */
 
-void expand(int old_fpb, int new_fpb);
-void shrink(int new_fpb);
+void forEachAction(std::function<void(const Action*)> f);
 
-/* getNextAction
-Returns 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 with 'mask' to ignore bytes. Useful for MIDI key_release. 
-Mask example:
+/* getActionsOnFrame
+Returns a vector of actions recorded on frame 'f'. */
 
-       iValue = 0x803D3F00
-       mask   = 0x0000FF00  // ignore byte 3
-       action = 0x803D3200  // <--- this action will be found */
+std::vector<const Action*> getActionsOnFrame(Frame f);
 
-int getNextAction(int chan, char action, int frame, struct action** out,
-       uint32_t iValue=0, uint32_t mask=0);
+/* getActionsOnChannel
+Returns a vector of actions belonging to channel 'ch'. */
 
-/* getAction
-Returns a pointer to action in chan 'chan' of type 'action' at frame 'frame'. */
+std::vector<const Action*> getActionsOnChannel(int ch);
 
-int getAction(int chan, char action, int frame, struct action** out);
+/* getClosestAction
+Given a frame 'f' returns the closest action. */
 
-/* getActionsOnFrame
-Returns a vector of actions that occur on frame 'frame'. */
+const Action* getClosestAction(int channel, Frame f, int type);
 
-std::vector<action*> getActionsOnFrame(int frame);
 
-/* start/stopOverdub
-These functions are used when you overwrite existing actions. For example:
-pressing Mute button on a channel with some existing mute actions. */
+int getLatestActionId();
 
-void startOverdub(int chan, char action, int frame, unsigned bufferSize);
-void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t* mixerMutex);
+/* getActionMap
+Returns a copy of the internal action map. Used only by recorderHandler. */
 
-/* forEachAction
-Applies a read-only callback on each action recorded. */
+ActionMap getActionMap();
 
-void forEachAction(std::function<void(const action*)> f);
 }}}; // giada::m::recorder::
 
+
 #endif
diff --git a/src/core/recorderHandler.cpp b/src/core/recorderHandler.cpp
new file mode 100644 (file)
index 0000000..7879be6
--- /dev/null
@@ -0,0 +1,290 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <algorithm>
+#include <cmath>
+#include <cassert>
+#include "../utils/log.h"
+#include "../utils/ver.h"
+#include "recorder.h"
+#include "action.h"
+#include "clock.h"
+#include "const.h"
+#include "recorderHandler.h"
+
+
+namespace giada {
+namespace m {
+namespace recorderHandler
+{
+namespace
+{
+std::vector<const Action*> recs_;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+const Action* getActionById_(int id, const recorder::ActionMap& source)
+{
+       for (auto& kv : source)
+               for (const Action* action : kv.second)
+                       if (action->id == id)
+                               return action;
+       return nullptr;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* areComposite_
+Composite: NOTE_ON + NOTE_OFF on the same note. */
+
+bool areComposite_(const Action* a1, const Action* a2)
+{
+       return a1->event.getStatus() == MidiEvent::NOTE_ON  &&
+              a2->event.getStatus() == MidiEvent::NOTE_OFF &&
+              a1->event.getNote() == a2->event.getNote()   &&
+              a1->channel == a2->channel;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* consolidate_
+Given an action 'a1' tries to find the matching NOTE_OFF. This algorithm must
+start searching from the element next to 'a1': since live actions are recorded
+in linear sequence, the potential partner of 'a1' always lies beyond a1 itself. 
+Without this trick (i.e. if it loops from vector.begin() each time) the
+algorithm would end up matching wrong partners. */
+
+void consolidate_(const Action* a1, size_t i)
+{
+       for (auto it = recs_.begin() + i; it != recs_.end(); ++it) {
+
+               const Action* a2 = *it;
+
+               if (!areComposite_(a1, a2))
+                       continue;
+
+               const_cast<Action*>(a1)->next = a2;
+               const_cast<Action*>(a2)->prev = a1;
+
+               break;
+       }               
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void consolidate_()
+{
+       for (auto it = recs_.begin(); it != recs_.end(); ++it)
+               consolidate_(*it, it - recs_.begin());  // Pass current index
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPatch_DEPR_(const std::vector<patch::action_t>& pactions)
+{
+       for (const patch::action_t paction : pactions)
+               recs_.push_back(recorder::makeAction(-1, paction.channel, paction.frame, MidiEvent(paction.event)));
+       
+       consolidate();
+}
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+bool isBoundaryEnvelopeAction(const Action* a)
+{
+       assert(a->prev != nullptr);
+       assert(a->next != nullptr);
+       return a->prev->frame > a->frame || a->next->frame < a->frame;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateBpm(float oldval, float newval, int oldquanto)
+{
+       recorder::updateKeyFrames([=](Frame old) 
+       {
+               /* The division here cannot be precise. A new frame can be 44099 and the 
+               quantizer set to 44100. That would mean two recs completely useless. So we 
+               compute a reject value ('scarto'): if it's lower than 6 frames the new frame 
+               is collapsed with a quantized frame. FIXME - maybe 6 frames are too low. */
+               Frame frame = (old / newval) * oldval;
+               if (frame != 0) {
+                       Frame delta = oldquanto % frame;
+                       if (delta > 0 && delta <= 6)
+                               frame = frame + delta;
+               }
+               return frame;
+       });
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateSamplerate(int systemRate, int patchRate)
+{
+       if (systemRate == patchRate)
+               return;
+
+       float ratio = systemRate / (float) patchRate;
+
+       recorder::updateKeyFrames([=](Frame old) { return floorf(old * ratio); });
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool cloneActions(int chanIndex, int newChanIndex)
+{
+       recorder::ActionMap temp = recorder::getActionMap();
+
+       bool cloned   = false;
+       int  actionId = recorder::getLatestActionId(); 
+
+       recorder::forEachAction([&](const Action* a) 
+       {
+               if (a->channel == chanIndex) {
+                       Action* clone = new Action(*a);
+                       clone->id      = ++actionId;
+                       clone->channel = newChanIndex;
+                       temp[clone->frame].push_back(clone);
+                       cloned = true;
+               }
+       });
+
+       recorder::updateActionId(actionId);
+       recorder::updateActionMap(std::move(temp));
+
+       return cloned;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void liveRec(int channel, MidiEvent e)
+{
+       assert(e.isNoteOnOff()); // Can't record any other kind of events for now
+       recs_.push_back(recorder::makeAction(-1, channel, clock::getCurrentFrame(), e));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void consolidate()
+{
+       consolidate_();
+       recorder::rec(recs_);
+       recs_.clear();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void writePatch(int chanIndex, std::vector<patch::action_t>& pactions)
+{
+       recorder::forEachAction([&] (const Action* a) 
+       {
+               if (a->channel != chanIndex) 
+                       return;
+               pactions.push_back(patch::action_t { 
+                       a->id, 
+                       a->channel, 
+                       a->frame, 
+                       a->event.getRaw(), 
+                       a->prev != nullptr ? a->prev->id : -1,
+                       a->next != nullptr ? a->next->id : -1
+               });
+       });
+}
+
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void readPatch(const std::vector<patch::action_t>& pactions)
+{
+       if (u::ver::isLess(patch::versionMajor, patch::versionMinor, patch::versionPatch, 0, 15, 3)) {
+               readPatch_DEPR_(pactions);
+               return;
+       }
+
+       recorder::ActionMap temp = recorder::getActionMap();
+
+       /* First pass: add actions with no relationship (no prev/next). */
+
+       for (const patch::action_t paction : pactions) {
+               temp[paction.frame].push_back(recorder::makeAction(
+                       paction.id, 
+                       paction.channel, 
+                       paction.frame, 
+                       MidiEvent(paction.event)));
+               recorder::updateActionId(paction.id + 1);
+       }
+
+       /* Second pass: fill in previous and next actions, if any. */
+
+       for (const patch::action_t paction : pactions) {
+               if (paction.next == -1 && paction.prev == -1) 
+                       continue;
+               Action* curr = const_cast<Action*>(getActionById_(paction.id, temp));
+               assert(curr != nullptr);
+               if (paction.next != -1) {
+                       curr->next = getActionById_(paction.next, temp);
+                       assert(curr->next != nullptr);
+               }
+               if (paction.prev != -1) {
+                       curr->prev = getActionById_(paction.prev, temp);
+                       assert(curr->prev != nullptr);
+               }
+       }
+
+       recorder::updateActionMap(std::move(temp));
+}
+}}}; // giada::m::recorderHandler::
+
+
diff --git a/src/core/recorderHandler.h b/src/core/recorderHandler.h
new file mode 100644 (file)
index 0000000..7b256a7
--- /dev/null
@@ -0,0 +1,76 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef G_RECORDER_HANDLER_H
+#define G_RECORDER_HANDLER_H
+
+
+#include "midiEvent.h"
+#include "patch.h"
+
+
+namespace giada {
+namespace m 
+{
+struct Action;
+
+namespace recorderHandler
+{
+bool isBoundaryEnvelopeAction(const Action* a);
+
+/* updateBpm
+Changes actions position by calculating the new bpm value. */
+
+void updateBpm(float oldval, float newval, int oldquanto);
+
+/* updateSamplerate
+Changes actions position by taking in account the new samplerate. If 
+f_system == f_patch nothing will change, otherwise the conversion is 
+mandatory. */
+
+void updateSamplerate(int systemRate, int patchRate);
+
+/* cloneActions
+Clones actions in channel 'chanIndex', giving them a new channel index. Returns
+whether any action has been cloned. */
+
+bool cloneActions(int chanIndex, int newChanIndex);
+
+/* liveRec
+Records a user-generated action. NOTE_ON or NOTE_OFF only for now. */
+
+void liveRec(int channel, MidiEvent e);
+
+void consolidate();
+
+void writePatch(int chanIndex, std::vector<patch::action_t>& pactions);
+void readPatch(const std::vector<patch::action_t>& pactions);
+
+}}}; // giada::m::recorderHandler::
+
+
+#endif
index 8139a7c55e850e6a42b04c99ad9d9c02423f8755..b352430b9bea437ed031797e0fc8b1f71cdd3be9 100644 (file)
 
 
 using std::string;
-using namespace giada;
-using namespace giada::m;
 
 
+namespace giada {
+namespace m 
+{
 SampleChannel::SampleChannel(bool inputMonitor, int bufferSize)
        : Channel          (ChannelType::SAMPLE, ChannelStatus::EMPTY, bufferSize),
-               mode             (ChannelMode::SINGLE_BASIC),
-               wave             (nullptr),
-               tracker          (0),
-               trackerPreview   (0),
-               shift            (0),
-               qWait              (false),
-               inputMonitor     (inputMonitor),
-               boost            (G_DEFAULT_BOOST),
-               pitch            (G_DEFAULT_PITCH),
-               begin            (0),
-               end              (0),
-               midiInReadActions(0x0),
-               midiInPitch      (0x0),
-               rsmp_state       (nullptr)
+         mode             (ChannelMode::SINGLE_BASIC),
+         wave             (nullptr),
+         tracker          (0),
+         trackerPreview   (0),
+         shift            (0),
+         qWait            (false),
+         inputMonitor     (inputMonitor),
+         boost            (G_DEFAULT_BOOST),
+         pitch            (G_DEFAULT_PITCH),
+         begin            (0),
+         end              (0),
+         midiInReadActions(0x0),
+         midiInPitch      (0x0),
+         rsmp_state       (nullptr)
 {
        rsmp_state = src_new(SRC_LINEAR, G_MAX_IO_CHANS, nullptr);
        if (rsmp_state == nullptr) {
@@ -99,7 +100,7 @@ void SampleChannel::copy(const Channel* src_, pthread_mutex_t* pluginMutex)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::parseEvents(m::mixer::FrameEvents fe)
+void SampleChannel::parseEvents(mixer::FrameEvents fe)
 {
        sampleChannelProc::parseEvents(this, fe);
        sampleChannelRec::parseEvents(this, fe);
@@ -223,8 +224,16 @@ void SampleChannel::setMute(bool value)
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::process(giada::m::AudioBuffer& out, 
-       const giada::m::AudioBuffer& in, bool audible, bool running)
+void SampleChannel::setSolo(bool value)
+{
+       sampleChannelProc::setSolo(this, value);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void SampleChannel::process(AudioBuffer& out, const AudioBuffer& in, 
+       bool audible, bool running)
 {
        sampleChannelProc::process(this, out, in, audible, running);
 }
@@ -233,10 +242,10 @@ void SampleChannel::process(giada::m::AudioBuffer& out,
 /* -------------------------------------------------------------------------- */
 
 
-void SampleChannel::readPatch(const string& basePath, int i)
+void SampleChannel::readPatch(const string& basePath, const patch::channel_t& pch)
 {
-       Channel::readPatch("", i);
-       channelManager::readPatch(this, basePath, i);
+       Channel::readPatch("", pch);
+       channelManager::readPatch(this, basePath, pch);
 }
 
 
@@ -387,12 +396,12 @@ float SampleChannel::getBoost() const
 void SampleChannel::empty()
 {
        status     = ChannelStatus::EMPTY;
-  begin      = 0;
-  end        = 0;
-  tracker    = 0;
-  volume     = G_DEFAULT_VOL;
-  boost      = G_DEFAULT_BOOST;
-  hasActions = false;
+       begin      = 0;
+       end        = 0;
+       tracker    = 0;
+       volume     = G_DEFAULT_VOL;
+       boost      = G_DEFAULT_BOOST;
+       hasActions = false;
        delete wave;
        wave = nullptr;
        sendMidiLstatus();
@@ -408,7 +417,6 @@ void SampleChannel::pushWave(Wave* w)
        wave   = w;
        begin  = 0;
        end    = wave->getSize() - 1;
-       name   = wave->getBasename();
        sendMidiLstatus();
 }
 
@@ -425,7 +433,7 @@ bool SampleChannel::canInputRec()
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::fillBuffer(giada::m::AudioBuffer& dest, int start, int offset)
+int SampleChannel::fillBuffer(AudioBuffer& dest, int start, int offset)
 {
        if (pitch == 1.0) return fillBufferCopy(dest, start, offset);
        else              return fillBufferResampled(dest, start, offset);
@@ -435,7 +443,7 @@ int SampleChannel::fillBuffer(giada::m::AudioBuffer& dest, int start, int offset
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::fillBufferResampled(giada::m::AudioBuffer& dest, int start, int offset)
+int SampleChannel::fillBufferResampled(AudioBuffer& dest, int start, int offset)
 {
        rsmp_data.data_in       = wave->getFrame(start);        // Source data
        rsmp_data.input_frames  = end - start;                  // How many readable frames
@@ -452,7 +460,7 @@ int SampleChannel::fillBufferResampled(giada::m::AudioBuffer& dest, int start, i
 /* -------------------------------------------------------------------------- */
 
 
-int SampleChannel::fillBufferCopy(giada::m::AudioBuffer& dest, int start, int offset)
+int SampleChannel::fillBufferCopy(AudioBuffer& dest, int start, int offset)
 {
        int used = dest.countFrames() - offset;
        if (used + start > wave->getSize())
@@ -486,4 +494,6 @@ bool SampleChannel::isAnySingleMode() const
 bool SampleChannel::isOnLastFrame() const
 {
        return tracker >= end;
-}
\ No newline at end of file
+}
+
+}} // giada::m::
index 857e8e1cdc316f4c71fba410bdff83deb6118614..4514f0e28f9104a09619cb67d870b3f00c8e9a88 100644 (file)
 #include "channel.h"
 
 
-class Patch;
 class Wave;
 
 
+namespace giada {
+namespace m 
+{
 class SampleChannel : public Channel
 {
 public:
@@ -48,10 +50,9 @@ public:
 
        void copy(const Channel* src, pthread_mutex_t* pluginMutex) override;
        void prepareBuffer(bool running) override;
-       void parseEvents(giada::m::mixer::FrameEvents fe) override;
-       void process(giada::m::AudioBuffer& out, const giada::m::AudioBuffer& in,
-               bool audible, bool running) override;
-       void readPatch(const std::string& basePath, int i) override;
+       void parseEvents(mixer::FrameEvents fe) override;
+       void process(AudioBuffer& out, const AudioBuffer& in, bool audible, bool running) override;
+       void readPatch(const std::string& basePath, const patch::channel_t& pch) override;
        void writePatch(int i, bool isProject) override;
 
        void start(int frame, bool doQuantize, int velocity) override;
@@ -61,6 +62,7 @@ public:
        bool recordKill() override;
        void recordStop() override;
        void setMute(bool value) override;
+       void setSolo(bool value) override;
        void startReadingActions(bool treatRecsAsLoops, bool recsStopOnChanHalt) override;
        void stopReadingActions(bool running, bool treatRecsAsLoops, 
                bool recsStopOnChanHalt) override;
@@ -91,7 +93,7 @@ public:
        Returns how many frames have been used from the original Wave data. It also
        resamples data if pitch != 1.0f. */
 
-       int fillBuffer(giada::m::AudioBuffer& dest, int start, int offset);
+       int fillBuffer(AudioBuffer& dest, int start, int offset);
 
        /* pushWave
        Adds a new wave to an existing channel. */
@@ -113,9 +115,9 @@ public:
        /* bufferPreview
        Extra buffer for audio preview. */
 
-       giada::m::AudioBuffer bufferPreview;
+       AudioBuffer bufferPreview;
        
-       giada::ChannelMode mode;
+       ChannelMode mode;
        
        Wave* wave;
        int   tracker;         // chan position
@@ -146,8 +148,11 @@ private:
        SRC_STATE* rsmp_state;
        SRC_DATA   rsmp_data;
 
-       int fillBufferResampled(giada::m::AudioBuffer& dest, int start, int offset);
-       int fillBufferCopy     (giada::m::AudioBuffer& dest, int start, int offset);
+       int fillBufferResampled(AudioBuffer& dest, int start, int offset);
+       int fillBufferCopy     (AudioBuffer& dest, int start, int offset);
 };
 
+}} // giada::m::
+
+
 #endif
index aa23584f467665497576247b7f03b40ed7c31963..ef3569ecf1ad30d86817c0fffb8d83591e97be59 100644 (file)
@@ -31,6 +31,7 @@
 #include "pluginHost.h"
 #include "sampleChannel.h"
 #include "sampleChannelProc.h"
+#include "mixerHandler.h"
 
 
 namespace giada {
@@ -188,7 +189,8 @@ void processData_(SampleChannel* ch, m::AudioBuffer& out, const m::AudioBuffer&
        bool running)
 {
        assert(out.countSamples() == ch->buffer.countSamples());
-       assert(in.countSamples()  == ch->buffer.countSamples());
+       if (in.isAllocd())
+               assert(in.countSamples() == ch->buffer.countSamples());
 
        /* If armed and input buffer is not empty (i.e. input device available) and
        input monitor is on, copy input buffer to channel buffer: this enables the 
@@ -356,6 +358,10 @@ void rewindBySeq(SampleChannel* ch)
 void setMute(SampleChannel* ch, bool value)
 {
        ch->mute = value;
+
+       // This is for processing playing_inaudible
+       ch->sendMidiLstatus();  
+
        ch->sendMidiLmute();
 }
 
@@ -363,6 +369,23 @@ void setMute(SampleChannel* ch, bool value)
 /* -------------------------------------------------------------------------- */
 
 
+void setSolo(SampleChannel* ch, bool value)
+{
+       ch->solo = value;
+       m::mh::updateSoloCount();
+
+       // This is for processing playing_inaudible
+       for (Channel* channel : mixer::channels)                
+               channel->sendMidiLstatus();
+
+       ch->sendMidiLsolo();
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void start(SampleChannel* ch, int localFrame, bool doQuantize, int velocity)
 {
        /* For one-shot modes, velocity drives the internal volume. */
@@ -427,15 +450,26 @@ void start(SampleChannel* ch, int localFrame, bool doQuantize, int velocity)
 
 void prepareBuffer(SampleChannel* ch, bool running)
 {
-       if (!ch->hasData())
-               return;
+       namespace um = u::math;
+
        ch->buffer.clear();
-       if (ch->isPlaying()) {
-               int framesUsed = ch->fillBuffer(ch->buffer, ch->tracker, 0);
-               ch->tracker += framesUsed;
-               if (ch->isOnLastFrame())
-                       onLastFrame_(ch, framesUsed * (1 / ch->pitch), running);
+
+       if (!ch->hasData() || !ch->isPlaying())
+               return;
+
+       Frame framesUsed = ch->fillBuffer(ch->buffer, ch->tracker, 0);
+       ch->tracker += framesUsed;
+
+       /* The "framesUsed * (1 / ch->pitch)" operation might yield results greater
+       than the current buffer size. So clamping is mandatory. */
+
+       if (ch->isOnLastFrame()) {
+               Frame min  = 0; 
+               Frame max  = ch->buffer.countFrames() - 1;
+               framesUsed = static_cast<Frame>(framesUsed * (1 / ch->pitch));
+               onLastFrame_(ch, um::bound(framesUsed, min, max, max), running);
        }
+
 }
 
 
@@ -464,4 +498,4 @@ void process(SampleChannel* ch, m::AudioBuffer& out, const m::AudioBuffer& in,
        if (ch->isPreview())
                processPreview_(ch, out);
 }
-}}};
\ No newline at end of file
+}}};
index 0c95a69511b1321f66293a098f34f32c675bf357..5f14e852e1d922a24763c45932e251b17a37a84a 100644 (file)
 #include "types.h"
 
 
+namespace giada {
+namespace m 
+{
 class SampleChannel;
 
-
-namespace giada {
-namespace m {
 namespace sampleChannelProc
 {
 /**/
@@ -50,8 +50,8 @@ Parses events gathered by Mixer::masterPlay(). */
 void parseEvents(SampleChannel* ch, mixer::FrameEvents ev);
 
 /**/
-void process(SampleChannel* ch, giada::m::AudioBuffer& out
-       const giada::m::AudioBuffer& in, bool audible, bool running);
+void process(SampleChannel* ch, AudioBuffer& out, const AudioBuffer& in
+    bool audible, bool running);
 
 /* kill
 Stops a channel abruptly. */
@@ -85,7 +85,8 @@ actions from Recorder. */
 void start(SampleChannel* ch, int localFrame, bool doQuantize, int velocity);
 
 void setMute(SampleChannel* ch, bool value);
+void setSolo(SampleChannel* ch, bool value);
 }}};
 
 
-#endif
\ No newline at end of file
+#endif
index 91db54165395dd437a185d03b6539d67b43d7d05..ec8a7a8ccf397a026c26ba44d7b855ec9b565436 100644 (file)
 
 
 #include <cassert>
+#include "../utils/math.h"
+#include "recorder.h"
+#include "recorderHandler.h"
 #include "const.h"
 #include "conf.h"
 #include "clock.h"
+#include "action.h"
 #include "kernelAudio.h"
 #include "sampleChannel.h"
 #include "sampleChannelRec.h"
@@ -69,7 +73,14 @@ void onFirstBeat_(SampleChannel* ch, bool recsStopOnChanHalt)
 
 bool recorderCanRec_(SampleChannel* ch)
 {
-       return recorder::canRec(ch, clock::isRunning(), mixer::recording);
+       /* Can record on a channel if:
+               - recorder is on
+               - mixer is running
+               - mixer is not recording a take somewhere
+               - channel is MIDI or SAMPLE type with data in it  */
+
+       return recorder::isActive() && clock::isRunning() && !mixer::recording && 
+               (ch->type == ChannelType::MIDI || (ch->type == ChannelType::SAMPLE && ch->hasData()));
 }
 
 
@@ -79,48 +90,31 @@ bool recorderCanRec_(SampleChannel* ch)
 /* calcVolumeEnv
 Computes any changes in volume done via envelope tool. */
 
-void calcVolumeEnv_(SampleChannel* ch, int globalFrame)
+void calcVolumeEnv_(SampleChannel* ch, const Action* a1)
 {
-       /* method: check this frame && next frame, then calculate delta */
+       assert(a1 != nullptr);
+       assert(a1->next != nullptr);
 
-       recorder::action* a0 = nullptr;
-       recorder::action* a1 = nullptr;
-       int res;
+       const Action* a2 = a1->next;
 
-       /* get this action on frame 'frame'. It's unlikely that the action
-        * is not found. */
+       double vf1 = u::math::map<int, double>(a1->event.getVelocity(), 0, G_MAX_VELOCITY, 0, 1.0);
+       double vf2 = u::math::map<int, double>(a2->event.getVelocity(), 0, G_MAX_VELOCITY, 0, 1.0);
 
-       res = recorder::getAction(ch->index, G_ACTION_VOLUME, globalFrame, &a0);
-
-       assert(res != 0);
-
-       /* get the action next to this one.
-        * res == -1: a1 not found, this is the last one. Rewind the search
-        * and use action at frame number 0 (actions[0]).
-        * res == -2 G_ACTION_VOLUME not found. This should never happen */
-
-       res = recorder::getNextAction(ch->index, G_ACTION_VOLUME, globalFrame, &a1);
-       if (res == -1)
-               res = recorder::getAction(ch->index, G_ACTION_VOLUME, 0, &a1);
-
-       assert(res != -2);
-
-       ch->volume_i = a0->fValue;
-       ch->volume_d = ((a1->fValue - a0->fValue) / (a1->frame - a0->frame)) * 1.003f;
+       ch->volume_i = vf1;
+       ch->volume_d = a2->frame == a1->frame ? 0 : (vf2 - vf1) / (a2->frame - a1->frame);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void parseAction_(SampleChannel* ch, const recorder::action* a, int localFrame, 
-       int globalFrame)
+void parseAction_(SampleChannel* ch, const Action* a, int localFrame, int globalFrame)
 {
        if (!ch->readActions)
                return;
 
-       switch (a->type) {
-               case G_ACTION_KEYPRESS:
+       switch (a->event.getStatus()) {
+               case MidiEvent::NOTE_ON:
                        if (ch->isAnySingleMode()) {
                                ch->start(localFrame, false, 0);
                                /* This is not a user-generated event, so fill the first chunk of buffer. 
@@ -130,16 +124,16 @@ void parseAction_(SampleChannel* ch, const recorder::action* a, int localFrame,
                                        ch->tracker += ch->fillBuffer(ch->buffer, ch->tracker, localFrame);
                        }
                        break;
-               case G_ACTION_KEYREL:
+               case MidiEvent::NOTE_OFF:
                        if (ch->isAnySingleMode())
                                ch->stop();
                        break;
-               case G_ACTION_KILL:
+               case MidiEvent::NOTE_KILL:
                        if (ch->isAnySingleMode())
                                ch->kill(localFrame);
                        break;
-               case G_ACTION_VOLUME:
-                       calcVolumeEnv_(ch, globalFrame);
+               case MidiEvent::ENVELOPE:
+                       calcVolumeEnv_(ch, a);
                        break;
        }
 }
@@ -153,15 +147,11 @@ void recordKeyPressAction_(SampleChannel* ch)
        if (!recorderCanRec_(ch))
                return;
 
-       /* SINGLE_PRESS mode needs overdub. Also, disable reading actions while 
-       overdubbing. */
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               recorder::startOverdub(ch->index, G_ACTION_KEYS, clock::getCurrentFrame(), 
-                       kernelAudio::getRealBufSize());
+       /* Disable reading actions while recording SINGLE_PRESS mode. */
+       if (ch->mode == ChannelMode::SINGLE_PRESS)
                ch->readActions = false;
-       }
-       else
-               recorder::rec(ch->index, G_ACTION_KEYPRESS, clock::getCurrentFrame());
+       
+       recorderHandler::liveRec(ch->index, MidiEvent(MidiEvent::NOTE_ON, 0, 0));
        ch->hasActions = true;
 }
 
@@ -191,8 +181,8 @@ void parseEvents(SampleChannel* ch, mixer::FrameEvents fe)
        quantize_(ch, fe.quantoPassed);
        if (fe.onFirstBeat)
                onFirstBeat_(ch, conf::recsStopOnChanHalt);
-       for (const recorder::action* action : fe.actions)
-               if (action->chan == ch->index)
+       for (const Action* action : fe.actions)
+               if (action->channel == ch->index)
                        parseAction_(ch, action, fe.frameLocal, fe.frameGlobal);
 }
 
@@ -230,9 +220,9 @@ bool recordStart(SampleChannel* ch, bool canQuantize)
 
 bool recordKill(SampleChannel* ch)
 {
-       /* Don't record G_ACTION_KILL actions for LOOP channels. */
+       /* Don't record NOTE_KILL actions for LOOP channels. */
        if (recorderCanRec_(ch) && !ch->isAnyLoopMode()) {
-               recorder::rec(ch->index, G_ACTION_KILL, clock::getCurrentFrame());
+               recorder::rec(ch->index, clock::getCurrentFrame(), MidiEvent(MidiEvent::NOTE_KILL, 0, 0));
                ch->hasActions = true;
        }
        return true;
@@ -246,10 +236,8 @@ void recordStop(SampleChannel* ch)
 {
        /* Record a stop event only if channel is SINGLE_PRESS. For any other mode 
        the stop event is meaningless. */
-       if (recorderCanRec_(ch) && ch->mode == ChannelMode::SINGLE_PRESS) {
-               recorder::stopOverdub(clock::getCurrentFrame(), clock::getFramesInLoop(),
-                       &mixer::mutex);
-       }
+       if (recorderCanRec_(ch) && ch->mode == ChannelMode::SINGLE_PRESS)
+               recorderHandler::liveRec(ch->index, MidiEvent(MidiEvent::NOTE_OFF, 0, 0));
 }
 
 
index 6694b2e8f0c9d8b80be89523e11ec393909341bf..720a7483249e709cc0bf8a191dc874aaf188f3a6 100644 (file)
 #define G_SAMPLE_CHANNEL_REC_H
 
 
-class SampleChannel;
 
 
 namespace giada {
-namespace m {
+namespace m 
+{
+class SampleChannel;
+
 namespace sampleChannelRec
 {
 void parseEvents(SampleChannel* ch, mixer::FrameEvents fe);
index 1276dc613b3cf29dac9cd9fe8a6d4c3ff8c716d0..40a68d4e6abd4272231556657572824b573409ff 100644 (file)
@@ -61,12 +61,12 @@ float* Wave::operator [](int offset) const
 Wave::Wave(const Wave& other)
 :      m_rate    (other.m_rate),
        m_bits    (other.m_bits),       
-       m_logical (true),   // a cloned wave does not exist on disk
+       m_logical (true),   // A cloned wave does not exist on disk
        m_edited  (false),
        m_path    (other.m_path)
 {
        buffer.alloc(other.getSize(), other.getChannels());
-       buffer.copyData(other.getFrame(0), other.getSize(), other.getChannels());
+       buffer.copyData(other.getFrame(0), other.getSize());
 }
 
 
diff --git a/src/glue/actionEditor.cpp b/src/glue/actionEditor.cpp
new file mode 100644 (file)
index 0000000..22c8d22
--- /dev/null
@@ -0,0 +1,339 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#include <cassert>
+#include "../core/clock.h"
+#include "../core/const.h"
+#include "../core/sampleChannel.h"
+#include "../core/midiChannel.h"
+#include "../core/recorderHandler.h"
+#include "../core/recorder.h"
+#include "../core/action.h"
+#include "recorder.h"
+#include "actionEditor.h"
+
+
+using std::vector;
+
+
+namespace giada {
+namespace c {
+namespace actionEditor
+{
+namespace
+{
+Frame fixVerticalEnvActions_(Frame f, const m::Action* a1, const m::Action* a2)
+{
+       if      (a1->frame == f) f += 1;
+       else if (a2->frame == f) f -= 1;
+       if (a1->frame == f || a2->frame == f)
+               return -1;
+       return f;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/* recordFirstEnvelopeAction_
+First action ever? Add actions at boundaries. */
+
+void recordFirstEnvelopeAction_(int channel, Frame frame, int value)
+{
+       namespace mr = m::recorder;
+
+       m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, G_MAX_VELOCITY);
+       m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
+       const m::Action* a1 = mr::rec(channel, 0, e1);  
+       const m::Action* a2 = mr::rec(channel, frame, e2);
+       const m::Action* a3 = mr::rec(channel, m::clock::getFramesInLoop() - 1, e1);
+       mr::updateSiblings(a1, a3, a2); // Circular loop (begin)
+       mr::updateSiblings(a2, a1, a3);
+       mr::updateSiblings(a3, a2, a1); // Circular loop (end)
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* recordNonFirstEnvelopeAction_
+Find action right before frame 'frame' and inject a new action in there. 
+Vertical envelope points are forbidden. */
+
+void recordNonFirstEnvelopeAction_(int channel, Frame frame, int value)
+{
+       namespace mr = m::recorder;
+
+       m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
+       const m::Action* a1 = mr::getClosestAction(channel, frame, m::MidiEvent::ENVELOPE);
+       const m::Action* a3 = a1->next;
+       assert(a1 != nullptr);
+       assert(a3 != nullptr);
+       frame = fixVerticalEnvActions_(frame, a1, a3);
+       if (frame == -1) // Vertical points, nothing to do here
+               return;
+       const m::Action* a2 = mr::rec(channel, frame, e2);
+       mr::updateSiblings(a2, a1, a3);
+}
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+void recordMidiAction(m::MidiChannel* ch, int note, int velocity, Frame f1, Frame f2)
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       if (f2 == 0)
+               f2 = f1 + G_DEFAULT_ACTION_SIZE;
+
+       /* Avoid frame overflow. */
+
+       int overflow = f2 - (m::clock::getFramesInLoop());
+       if (overflow > 0) {
+               f2 -= overflow;
+               f1 -= overflow;
+       }
+
+       m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, velocity);
+       m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, velocity);
+
+       const m::Action* a1 = mr::rec(ch->index, f1, e1);
+       const m::Action* a2 = mr::rec(ch->index, f2, e2);
+
+       mr::updateSiblings(a1, nullptr, a2);
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void deleteMidiAction(m::MidiChannel* ch, const m::Action* a)
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       assert(a != nullptr);
+       assert(a->event.getStatus() == m::MidiEvent::NOTE_ON);
+
+       /* Send a note-off first in case we are deleting it in a middle of a 
+       key_on/key_off sequence. */
+       
+       if (a->next != nullptr) {
+               ch->sendMidi(a->next, 0);
+               mr::deleteAction(a->next);
+       }
+       mr::deleteAction(a);
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateMidiAction(m::MidiChannel* ch, const m::Action* a, int note, int velocity, 
+       Frame f1, Frame f2)
+{
+       namespace mr = m::recorder;
+
+       mr::deleteAction(a->next);
+       mr::deleteAction(a);
+       
+       recordMidiAction(ch, note, velocity, f1, f2);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void recordSampleAction(const m::SampleChannel* ch, int type, Frame f1, Frame f2)
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       if (ch->mode == ChannelMode::SINGLE_PRESS) {
+               m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::NOTE_ON, 0, 0);
+               m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::NOTE_OFF, 0, 0);
+               const m::Action* a1 = mr::rec(ch->index, f1, e1);
+               const m::Action* a2 = mr::rec(ch->index, f2 == 0 ? f1 + G_DEFAULT_ACTION_SIZE : f2, e2);
+               mr::updateSiblings(a1, nullptr, a2);
+       }
+       else {
+               m::MidiEvent e1 = m::MidiEvent(type, 0, 0);
+               mr::rec(ch->index, f1, e1);
+       }
+       
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateSampleAction(m::SampleChannel* ch, const m::Action* a, int type, Frame f1, 
+       Frame f2)
+{
+       namespace mr = m::recorder;     
+
+       if (ch->mode == ChannelMode::SINGLE_PRESS)
+               mr::deleteAction(a->next);
+       mr::deleteAction(a);
+
+       recordSampleAction(ch, type, f1, f2);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void recordEnvelopeAction(m::Channel* ch, int frame, int value)
+{
+       namespace mr = m::recorder;     
+       namespace cr = c::recorder;     
+
+       assert(value >= 0 && value <= G_MAX_VELOCITY);
+
+       /* First action ever? Add actions at boundaries. Else, find action right
+       before frame 'f' and inject a new action in there. Vertical envelope points 
+       are forbidden for now. */
+
+       if (!mr::hasActions(ch->index, m::MidiEvent::ENVELOPE))
+               recordFirstEnvelopeAction_(ch->index, frame, value);
+       else 
+               recordNonFirstEnvelopeAction_(ch->index, frame, value);
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void deleteEnvelopeAction(m::Channel* ch, const m::Action* a)
+{
+       namespace mr  = m::recorder;
+       namespace cr  = c::recorder;
+       namespace mrh = m::recorderHandler;
+
+       assert(a != nullptr);
+
+       /* Delete a boundary action wipes out everything. If is volume, remember to
+       restore _i and _d members in channel. */
+
+       if (mrh::isBoundaryEnvelopeAction(a)) {
+               if (a->isVolumeEnvelope()) {
+                       ch->volume_i = 1.0;
+                       ch->volume_d = 0.0;
+               }
+               mr::clearActions(ch->index, a->event.getStatus());
+               return;
+       }
+
+       const m::Action* a1 = a->prev;
+       const m::Action* a3 = a->next; 
+
+       /* Original status:   a1--->a--->a3
+          Modified status:   a1-------->a3 */
+
+       mr::deleteAction(a);
+       mr::updateSiblings(a1, a1->prev, a3);
+       mr::updateSiblings(a3, a1, a3->next);
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateEnvelopeAction(m::Channel* ch, const m::Action* a, int frame, int value)
+{
+       namespace mr  = m::recorder;
+       namespace cr  = c::recorder;
+       namespace mrh = m::recorderHandler;
+
+       assert(a != nullptr);
+
+       /* Update the action directly if it is a boundary one. Else, delete the
+       previous one and record a new action. */
+
+       if (mrh::isBoundaryEnvelopeAction(a))
+               mr::updateEvent(a, m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value));
+       else {
+               deleteEnvelopeAction(ch, a);
+               recordEnvelopeAction(ch, frame, value); 
+       }
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);       
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void deleteSampleAction(m::SampleChannel* ch, const m::Action* a)
+{
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
+
+       assert(a != nullptr);
+
+       if (a->next != nullptr) // For ChannelMode::SINGLE_PRESS combo
+               mr::deleteAction(a->next);
+       mr::deleteAction(a);
+
+       cr::updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+vector<const m::Action*> getActions(const m::Channel* ch)
+{
+       return m::recorder::getActionsOnChannel(ch->index);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void updateVelocity(const m::MidiChannel* ch, const m::Action* a, int value)
+{
+       namespace mr = m::recorder;
+       
+       m::MidiEvent event(a->event);
+       event.setVelocity(value);
+
+       mr::updateEvent(a, event);
+}
+}}}; // giada::c::actionEditor::
diff --git a/src/glue/actionEditor.h b/src/glue/actionEditor.h
new file mode 100644 (file)
index 0000000..17fd7fb
--- /dev/null
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef G_GLUE_ACTION_EDITOR_H
+#define G_GLUE_ACTION_EDITOR_H
+
+
+#include <vector>
+#include "../core/types.h"
+
+
+namespace giada {
+namespace m
+{
+class Action;
+class SampleChannel;
+class MidiChannel;
+}
+namespace c {
+namespace actionEditor 
+{
+std::vector<const m::Action*> getActions(const m::Channel* ch);
+
+/* MIDI actions.  */
+
+void recordMidiAction(m::MidiChannel* ch, int note, int velocity, Frame f1, Frame f2=0);
+void deleteMidiAction(m::MidiChannel* ch, const m::Action* a);
+void updateMidiAction(m::MidiChannel* ch, const m::Action* a, int note, int velocity, 
+    Frame f1, Frame f2);
+void updateVelocity(const m::MidiChannel* ch, const m::Action* a, int value);
+
+/* Sample Actions. */
+
+void recordSampleAction(const m::SampleChannel* ch, int type, Frame f1, Frame f2=0);
+void deleteSampleAction(m::SampleChannel* ch, const m::Action* a);
+void updateSampleAction(m::SampleChannel* ch, const m::Action* a, int type, Frame f1, Frame f2=0);
+
+/* Envelope actions (only volume for now). */
+
+void recordEnvelopeAction(m::Channel* ch, int frame, int value);
+void deleteEnvelopeAction(m::Channel* ch, const m::Action* a);
+void updateEnvelopeAction(m::Channel* ch, const m::Action* a, int frame, int value);
+}}}; // giada::c::actionEditor::
+
+#endif
index aaa805cb486c6c2d29a7c654ac2f97dfd06a34e4..74db5c94b9ebf27a45f0845b2b90220e99957d09 100644 (file)
@@ -56,6 +56,7 @@
 #include "../core/channel.h"
 #include "../core/sampleChannel.h"
 #include "../core/midiChannel.h"
+#include "../core/recorder.h"
 #include "../core/plugin.h"
 #include "../core/waveManager.h"
 #include "main.h"
@@ -72,7 +73,7 @@ namespace giada {
 namespace c     {
 namespace channel 
 {
-int loadChannel(SampleChannel* ch, const string& fname)
+int loadChannel(m::SampleChannel* ch, const string& fname)
 {
        using namespace giada::m;
 
@@ -113,9 +114,9 @@ int loadChannel(SampleChannel* ch, const string& fname)
 /* -------------------------------------------------------------------------- */
 
 
-Channel* addChannel(int column, ChannelType type, int size)
+m::Channel* addChannel(int column, ChannelType type, int size)
 {
-       Channel* ch    = m::mh::addChannel(type);
+       m::Channel* ch = m::mh::addChannel(type);
        geChannel* gch = G_MainWin->keyboard->addChannel(column, ch, size);
        ch->guiChannel = gch;
        return ch;
@@ -125,13 +126,13 @@ Channel* addChannel(int column, ChannelType type, int size)
 /* -------------------------------------------------------------------------- */
 
 
-void deleteChannel(Channel* ch)
+void deleteChannel(m::Channel* ch)
 {
        using namespace giada::m;
 
        if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
                return;
-       recorder::clearChan(ch->index);
+       recorder::clearChannel(ch->index);
        ch->hasActions = false;
 #ifdef WITH_VST
        pluginHost::freeStack(pluginHost::CHANNEL, &mixer::mutex, ch);
@@ -147,7 +148,7 @@ void deleteChannel(Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void freeChannel(Channel* ch)
+void freeChannel(m::Channel* ch)
 {
        if (ch->isPlaying()) {
                if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
@@ -158,7 +159,7 @@ void freeChannel(Channel* ch)
                return;
 
        G_MainWin->keyboard->freeChannel(ch->guiChannel);
-       m::recorder::clearChan(ch->index);
+       m::recorder::clearChannel(ch->index);
        ch->empty();
 
        /* delete any related subwindow */
@@ -173,7 +174,7 @@ void freeChannel(Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void toggleArm(Channel* ch, bool gui)
+void toggleArm(m::Channel* ch, bool gui)
 {
        ch->armed = !ch->armed;
        if (!gui)
@@ -184,9 +185,9 @@ void toggleArm(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void toggleInputMonitor(Channel* ch)
+void toggleInputMonitor(m::Channel* ch)
 {
-       SampleChannel* sch = static_cast<SampleChannel*>(ch);
+       m::SampleChannel* sch = static_cast<m::SampleChannel*>(ch);
        sch->inputMonitor = !sch->inputMonitor;
 }
 
@@ -194,7 +195,7 @@ void toggleInputMonitor(Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-int cloneChannel(Channel* src)
+int cloneChannel(m::Channel* src)
 {
        using namespace giada::m;
 
@@ -213,7 +214,7 @@ int cloneChannel(Channel* src)
 /* -------------------------------------------------------------------------- */
 
 
-void setVolume(Channel* ch, float v, bool gui, bool editor)
+void setVolume(m::Channel* ch, float v, bool gui, bool editor)
 {
        ch->volume = v;
 
@@ -239,7 +240,7 @@ void setVolume(Channel* ch, float v, bool gui, bool editor)
 /* -------------------------------------------------------------------------- */
 
 
-void setPitch(SampleChannel* ch, float val)
+void setPitch(m::SampleChannel* ch, float val)
 {
        ch->setPitch(val);
        gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
@@ -254,7 +255,7 @@ void setPitch(SampleChannel* ch, float val)
 /* -------------------------------------------------------------------------- */
 
 
-void setPanning(SampleChannel* ch, float val)
+void setPanning(m::SampleChannel* ch, float val)
 {
        ch->setPan(val);
        gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
@@ -269,7 +270,7 @@ void setPanning(SampleChannel* ch, float val)
 /* -------------------------------------------------------------------------- */
 
 
-void toggleMute(Channel* ch, bool gui)
+void toggleMute(m::Channel* ch, bool gui)
 {
        ch->setMute(!ch->mute);
        if (!gui) {
@@ -283,10 +284,9 @@ void toggleMute(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void toggleSolo(Channel* ch, bool gui)
+void toggleSolo(m::Channel* ch, bool gui)
 {
-       ch->solo = !ch->solo;
-       m::mh::updateSoloCount();       
+       ch->setSolo(!ch->solo);
        if (!gui) {
                Fl::lock();
                ch->guiChannel->solo->value(ch->solo);
@@ -298,7 +298,7 @@ void toggleSolo(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void kill(Channel* ch)
+void kill(m::Channel* ch)
 {
        ch->kill(0); // on frame 0: it's a user-generated event
 }
@@ -307,7 +307,7 @@ void kill(Channel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void setBoost(SampleChannel* ch, float val)
+void setBoost(m::SampleChannel* ch, float val)
 {
        ch->setBoost(val);
        gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
@@ -322,7 +322,7 @@ void setBoost(SampleChannel* ch, float val)
 /* -------------------------------------------------------------------------- */
 
 
-void setName(Channel* ch, const string& name)
+void setName(m::Channel* ch, const string& name)
 {
        ch->name = name;
        ch->guiChannel->update();
@@ -332,7 +332,7 @@ void setName(Channel* ch, const string& name)
 /* -------------------------------------------------------------------------- */
 
 
-void toggleReadingActions(Channel* ch, bool gui)
+void toggleReadingActions(m::Channel* ch, bool gui)
 {
 
        /* When you call startReadingRecs with conf::treatRecsAsLoops, the
@@ -353,7 +353,7 @@ void toggleReadingActions(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void startReadingActions(Channel* ch, bool gui)
+void startReadingActions(m::Channel* ch, bool gui)
 {
        using namespace giada::m;
 
@@ -370,7 +370,7 @@ void startReadingActions(Channel* ch, bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void stopReadingActions(Channel* ch, bool gui)
+void stopReadingActions(m::Channel* ch, bool gui)
 {
        using namespace giada::m;
 
@@ -384,4 +384,4 @@ void stopReadingActions(Channel* ch, bool gui)
        }
 }
 
-}}}; // giada::c::channel::
\ No newline at end of file
+}}}; // giada::c::channel::
index 8f6c1f9b359b7790a7daa49b87d9197afea65e14..9c18db7f9f1a2dcf79c914d4114f015563e0c114 100644 (file)
@@ -1,4 +1,4 @@
-/* -----------------------------------------------------------------------------
+    /* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
 #include "../core/types.h"
 
 
-class Channel;
-class SampleChannel;
 class gdSampleEditor;
 
 
 namespace giada {
-namespace c     {
+namespace m
+{
+class Channel;
+class SampleChannel;
+}
+namespace c {
 namespace channel 
 {
 /* addChannel
 Adds an empty new channel to the stack. Returns the new channel. */
 
-Channel* addChannel(int column, ChannelType type, int size);
+m::Channel* addChannel(int column, ChannelType type, int size);
 
 /* loadChannel
 Fills an existing channel with a wave. */
 
-int loadChannel(SampleChannel* ch, const std::string& fname);
+int loadChannel(m::SampleChannel* ch, const std::string& fname);
 
 /* deleteChannel
 Removes a channel from Mixer. */
 
-void deleteChannel(Channel* ch);
+void deleteChannel(m::Channel* ch);
 
 /* freeChannel
 Unloads the sample from a sample channel. */
 
-void freeChannel(Channel* ch);
+void freeChannel(m::Channel* ch);
 
 /* cloneChannel
 Makes an exact copy of Channel *ch. */
 
-int cloneChannel(Channel* ch);
+int cloneChannel(m::Channel* ch);
 
 /* toggle/set*
 Toggles 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 toggleArm(Channel* ch, bool gui=true);
-void toggleInputMonitor(Channel* ch);
-void kill(Channel* ch);
-void toggleMute(Channel* ch, bool gui=true);
-void toggleSolo(Channel* ch, bool gui=true);
-void setVolume(Channel* ch, float v, bool gui=true, bool editor=false);
-void setName(Channel* ch, const std::string& name);
-void setPitch(SampleChannel* ch, float val);
-void setPanning(SampleChannel* ch, float val);
-void setBoost(SampleChannel* ch, float val);
+void toggleArm(m::Channel* ch, bool gui=true);
+void toggleInputMonitor(m::Channel* ch);
+void kill(m::Channel* ch);
+void toggleMute(m::Channel* ch, bool gui=true);
+void toggleSolo(m::Channel* ch, bool gui=true);
+void setVolume(m::Channel* ch, float v, bool gui=true, bool editor=false);
+void setName(m::Channel* ch, const std::string& name);
+void setPitch(m::SampleChannel* ch, float val);
+void setPanning(m::SampleChannel* ch, float val);
+void setBoost(m::SampleChannel* ch, float val);
 
 /* toggleReadingRecs
 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 toggleReadingActions(Channel* ch, bool gui=true);
-void startReadingActions(Channel* ch, bool gui=true);
-void stopReadingActions(Channel* ch, bool gui=true);
+void toggleReadingActions(m::Channel* ch, bool gui=true);
+void startReadingActions(m::Channel* ch, bool gui=true);
+void stopReadingActions(m::Channel* ch, bool gui=true);
 
 }}}; // giada::c::channel::
 
index 767473f47da82c224cfab8cd8953e3277c0b4190..d2f1ea4a1130c01f557e413acb7790795e8dc7fa 100644 (file)
@@ -45,6 +45,7 @@
 #include "../core/clock.h"
 #include "../core/sampleChannel.h"
 #include "../core/midiChannel.h"
+#include "../core/recorderHandler.h"
 #include "main.h"
 #include "channel.h"
 #include "transport.h"
@@ -55,10 +56,10 @@ extern gdMainWindow* G_MainWin;
 
 
 namespace giada {
-namespace c     {
+namespace c {
 namespace io 
 {
-void keyPress(Channel* ch, bool ctrl, bool shift, int velocity)
+void keyPress(m::Channel* ch, bool ctrl, bool shift, int velocity)
 {
        /* Everything occurs on frame 0 here: they are all user-generated events. */
        if (ctrl)
@@ -78,7 +79,7 @@ void keyPress(Channel* ch, bool ctrl, bool shift, int velocity)
 /* -------------------------------------------------------------------------- */
 
 
-void keyRelease(Channel* ch, bool ctrl, bool shift)
+void keyRelease(m::Channel* ch, bool ctrl, bool shift)
 {
        if (!ctrl && !shift) {
                ch->recordStop();
@@ -92,7 +93,7 @@ void keyRelease(Channel* ch, bool ctrl, bool shift)
 
 void startStopActionRec(bool gui)
 {
-       m::recorder::active ? stopActionRec(gui) : startActionRec(gui);
+       m::recorder::isActive() ? stopActionRec(gui) : startActionRec(gui);
 }
 
 
@@ -101,15 +102,13 @@ void startStopActionRec(bool gui)
 
 void startActionRec(bool gui)
 {
-       using namespace giada::m;
-
-       if (kernelAudio::getStatus() == false)
+       if (m::kernelAudio::getStatus() == false)
                return;
 
-       recorder::active = true;
+       m::recorder::enable();
 
-       if (!clock::isRunning())
-               glue_startSeq(false);  // update gui
+       if (!m::clock::isRunning())
+               c::transport::startSeq(false);  // update gui
 
        if (!gui) {
                Fl::lock();
@@ -124,13 +123,10 @@ void startActionRec(bool gui)
 
 void stopActionRec(bool gui)
 {
-       /* Stop the recorder and sort newly recorder actions. */
-
-       m::recorder::active = false;
-       m::recorder::sortActions();
+       m::recorder::disable();
+       m::recorderHandler::consolidate();
 
-       for (Channel* ch : m::mixer::channels)
-       {
+       for (m::Channel* ch : m::mixer::channels) {
                if (ch->type == ChannelType::MIDI)
                        continue;
                G_MainWin->keyboard->setChannelWithActions(static_cast<geSampleChannel*>(ch->guiChannel));
@@ -179,7 +175,7 @@ int startInputRec(bool gui)
        }
 
        if (!clock::isRunning())
-               glue_startSeq(false); // update gui anyway
+               transport::startSeq(false); // update gui anyway
 
        Fl::lock();
                if (!gui)
index 799a56ef3169a3e2ff55a9ef8e95177fa1af63d9..e8e8eee6f0472cdb385a312ac4286253c438a032 100644 (file)
 #define G_GLUE_IO_H
 
 
-class Channel;
-class SampleChannel;
-class MidiChannel;
-
 namespace giada {
-namespace c     {
+namespace m
+{
+class Plugin;
+class Channel;
+}
+namespace c {
 namespace io 
 {
 /* keyPress / keyRelease
@@ -49,8 +50,8 @@ Handle the key pressure, either via mouse/keyboard or MIDI. If gui is true the
 event comes from the main window (mouse, keyboard or MIDI), otherwise the event 
 comes from the action recorder. */
 
-void keyPress  (Channel* ch, bool ctrl, bool shift, int velocity);
-void keyRelease(Channel* ch, bool ctrl, bool shift);
+void keyPress  (m::Channel* ch, bool ctrl, bool shift, int velocity);
+void keyRelease(m::Channel* ch, bool ctrl, bool shift);
 
 /* start/stopActionRec
 Handles the action recording. If gui == true the signal comes from an user
index 95d1138e6189c0737ec2ed0963ee01e508e172ee..1aad7a041e67bbe8bd820d3e8366be3c05ff0e1c 100644 (file)
@@ -41,6 +41,8 @@
 #include "../core/clock.h"
 #include "../core/kernelMidi.h"
 #include "../core/kernelAudio.h"
+#include "../core/recorder.h"
+#include "../core/recorderHandler.h"
 #include "../core/conf.h"
 #include "../core/const.h"
 #ifdef WITH_VST
@@ -72,7 +74,7 @@ void setBpm_(float f, string s)
 
        float vPre = clock::getBpm();
        clock::setBpm(f);
-       recorder::updateBpm(vPre, f, clock::getQuanto());
+       recorderHandler::updateBpm(vPre, f, clock::getQuanto());
        mixer::allocVirtualInput(clock::getFramesInLoop());
 
        gu_refreshActionEditor();
@@ -133,29 +135,18 @@ void glue_setBpm(float f)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_setBeats(int beats, int bars, bool expand)
+void glue_setBeats(int beats, int bars)
 {
        /* Never change this stuff while recording audio */
 
        if (mixer::recording)
                return;
 
-       /* Temp vars to store old data (they are necessary) */
-
-       int oldBeats = clock::getBeats();
-       unsigned oldTotalFrames = clock::getFramesInLoop();
-
        clock::setBeats(beats);
        clock::setBars(bars);
        clock::updateFrameBars();
        mixer::allocVirtualInput(clock::getFramesInLoop());
 
-       /* Update recorded actions, if 'expand' required and an expansion is taking
-       place. */
-
-       if (expand && clock::getBeats() > oldBeats)
-               recorder::expand(oldTotalFrames, clock::getFramesInLoop());
-
        G_MainWin->mainTimer->setMeter(clock::getBeats(), clock::getBars());
        gu_refreshActionEditor();  // in case the action editor is open
 }
@@ -164,27 +155,6 @@ void glue_setBeats(int beats, int bars, bool expand)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_rewindSeq(bool gui, bool notifyJack)
-{
-       mh::rewindSequencer();
-
-       /* FIXME - potential desync when Quantizer is enabled from this point on.
-       Mixer would wait, while the following calls would be made regardless of its
-       state. */
-
-#ifdef __linux__
-       if (notifyJack)
-               kernelAudio::jackSetPosition(0);
-#endif
-
-       if (conf::midiSync == MIDI_SYNC_CLOCK_M)
-               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 void glue_quantize(int val)
 {
        clock::setQuantize(val);
@@ -229,7 +199,7 @@ void glue_clearAllSamples()
                ch->empty();
                ch->guiChannel->reset();
        }
-       recorder::init();
+       recorder::clearAll();
        return;
 }
 
@@ -239,7 +209,7 @@ void glue_clearAllSamples()
 
 void glue_clearAllActions()
 {
-       recorder::init();
+       recorder::clearAll();
        for (Channel* ch : mixer::channels)
                ch->hasActions = false;
        gu_updateControls();
@@ -255,7 +225,7 @@ void glue_resetToInitState(bool resetGui, bool createColumns)
        mixer::close();
        clock::init(conf::samplerate, conf::midiTCfps);
        mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
-       recorder::init();
+       recorder::init(&mixer::mutex);
 #ifdef WITH_VST
        pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex);
 #endif
@@ -274,15 +244,12 @@ void glue_resetToInitState(bool resetGui, bool createColumns)
 /* -------------------------------------------------------------------------- */
 
 
-/* never expand or shrink recordings (last param of setBeats = false):
- * this is live manipulation */
-
 void glue_beatsMultiply()
 {
-       glue_setBeats(clock::getBeats() * 2, clock::getBars(), false);
+       glue_setBeats(clock::getBeats() * 2, clock::getBars());
 }
 
 void glue_beatsDivide()
 {
-       glue_setBeats(clock::getBeats() / 2, clock::getBars(), false);
+       glue_setBeats(clock::getBeats() / 2, clock::getBars());
 }
index 5dc304d9a0c9d67bd5d0024a7ae9c23c390a3c2c..ef7c7941c26898e263bb24a79b0f0db918d60849 100644 (file)
@@ -46,7 +46,7 @@ Sets bpm value. Usually called from the Jack callback or non-UI components. */
 
 void glue_setBpm(float v);
 
-void glue_setBeats(int beats, int bars, bool expand);
+void glue_setBeats(int beats, int bars);
 void glue_quantize(int val);
 void glue_setOutVol(float v, bool gui=true);
 void glue_setInVol(float v, bool gui=true);
index d581fe2cc5604b7889db5fffb1e0a22e80699212..4b55afd0ce8d6c66fa881896358f518625e26df9 100644 (file)
 #ifdef WITH_VST
 
 
+namespace giada {
+namespace m
+{
 class Plugin;
 class Channel;
-
-
-namespace giada {
-namespace c     {
+}
+namespace c {
 namespace plugin 
 {
-Plugin* addPlugin(Channel* ch, int index, int stackType);
-void swapPlugins(Channel* ch, int indexP1, int indexP2, int stackType);
-void freePlugin(Channel* ch, int index, int stackType);
-void setParameter(Plugin* p, int index, float value, bool gui=true); 
-void setProgram(Plugin* p, int index);
+m::Plugin* addPlugin(m::Channel* ch, int index, int stackType);
+void swapPlugins(m::Channel* ch, int indexP1, int indexP2, int stackType);
+void freePlugin(m::Channel* ch, int index, int stackType);
+void setParameter(m::Plugin* p, int index, float value, bool gui=true); 
+void setProgram(m::Plugin* p, int index);
 
 /* setPluginPathCb
 Callback attached to the DirBrowser for adding new Plug-in search paths in the
index 47e5b56481d1639022d609c7c22318602538d692..2b166cbf45051ae008ea8bd4112d59c0f698e7b3 100644 (file)
@@ -33,7 +33,9 @@
 #include "../core/clock.h"
 #include "../core/kernelMidi.h"
 #include "../core/channel.h"
+#include "../core/recorderHandler.h"
 #include "../core/recorder.h"
+#include "../core/action.h"
 #include "../core/mixer.h"
 #include "../core/sampleChannel.h"
 #include "../core/midiChannel.h"
@@ -47,34 +49,15 @@ using namespace giada;
 
 
 namespace giada {
-namespace c     {
+namespace c {
 namespace recorder 
 {
-namespace
-{
-void updateChannel(geChannel* gch, bool refreshActionEditor=true)
-{
-       gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
-       if (gch->ch->type == ChannelType::SAMPLE) {
-               geSampleChannel* gsch = static_cast<geSampleChannel*>(gch);
-               gsch->ch->hasActions ? gsch->showActionButton() : gsch->hideActionButton();
-       }
-       if (refreshActionEditor)
-               gu_refreshActionEditor(); // refresh a.editor window, it could be open
-}
-}; // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
 void clearAllActions(geChannel* gch)
 {
        if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
                return;
-       m::recorder::clearChan(gch->ch->index);
+       gch->ch->kill(0);
+       m::recorder::clearChannel(gch->ch->index);
        updateChannel(gch);
 }
 
@@ -86,7 +69,7 @@ void clearVolumeActions(geChannel* gch)
 {
        if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
                return;
-       m::recorder::clearAction(gch->ch->index, G_ACTION_VOLUME);
+       m::recorder::clearActions(gch->ch->index, m::MidiEvent::ENVELOPE);
        updateChannel(gch);
 }
 
@@ -98,7 +81,10 @@ void clearStartStopActions(geChannel* gch)
 {
        if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
                return;
-       m::recorder::clearAction(gch->ch->index, G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL);
+       gch->ch->kill(0);
+       m::recorder::clearActions(gch->ch->index, m::MidiEvent::NOTE_ON);
+       m::recorder::clearActions(gch->ch->index, m::MidiEvent::NOTE_OFF);
+       m::recorder::clearActions(gch->ch->index, m::MidiEvent::NOTE_KILL);
        updateChannel(gch);
 }
 
@@ -106,305 +92,15 @@ void clearStartStopActions(geChannel* gch)
 /* -------------------------------------------------------------------------- */
 
 
-bool midiActionCanFit(int chan, int note, int frame_a, int frame_b)
-{
-       namespace mr = m::recorder;
-
-       /* TODO - This is insane, to say the least. Let's wait for recorder refactoring... */
-
-       vector<mr::Composite> comps = getMidiActions(chan);
-       for (mr::Composite c : comps)
-    if (frame_b >= c.a1.frame && c.a2.frame >= frame_a && m::MidiEvent(c.a1.iValue).getNote() == note)
-                       return false;
-       return true;
-}
-
-
-bool sampleActionCanFit(const SampleChannel* ch, int frame_a, int frame_b)
-{
-       namespace mr = m::recorder;
-
-       /* TODO - Even more insanity... Let's wait for recorder refactoring... */
-
-       vector<mr::Composite> comps = getSampleActions(ch);
-       for (mr::Composite c : comps)
-    if (frame_b >= c.a1.frame && c.a2.frame >= frame_a)
-                       return false;
-       return true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void recordMidiAction(int chan, int note, int velocity, int frame_a, int frame_b)
-{
-       if (frame_b == 0)
-               frame_b = frame_a + G_DEFAULT_ACTION_SIZE;
-
-       /* Avoid frame overflow. */
-
-       int overflow = frame_b - (m::clock::getFramesInLoop());
-       if (overflow > 0) {
-               frame_b -= overflow;
-               frame_a -= overflow;
-       }
-
-       /* Prepare MIDI events. Due to some nasty restrictions on the ancient Recorder,
-       checks for overlapping are done by the caller. TODO ... */
-
-       m::MidiEvent event_a = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, velocity);
-       m::MidiEvent event_b = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, velocity);
-
-       m::recorder::rec(chan, G_ACTION_MIDI, frame_a, event_a.getRaw());
-       m::recorder::rec(chan, G_ACTION_MIDI, frame_b, event_b.getRaw());               
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void deleteMidiAction(MidiChannel* ch, m::recorder::action a1, m::recorder::action a2)
-{
-       m::recorder::deleteAction(ch->index, a1.frame, G_ACTION_MIDI, true, 
-               &m::mixer::mutex, a1.iValue, 0.0);
-       
-       /* If action 1 is not orphaned, send a note-off first in case we are deleting 
-       it in a middle of a key_on/key_off sequence. Conversely, orphaned actions
-       should not play, so no need to fire the note-off. */
-       
-       if (a2.frame != -1) {
-               ch->sendMidi(a2.iValue);
-               m::recorder::deleteAction(ch->index, a2.frame, G_ACTION_MIDI, true, 
-                       &m::mixer::mutex, a2.iValue, 0.0);
-       }
-
-       ch->hasActions = m::recorder::hasActions(ch->index);
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void recordSampleAction(SampleChannel* ch, int type, int frame_a, int frame_b)
-{
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               m::recorder::rec(ch->index, G_ACTION_KEYPRESS, frame_a);
-               m::recorder::rec(ch->index, G_ACTION_KEYREL, frame_b == 0 ? frame_a + G_DEFAULT_ACTION_SIZE : frame_b);
-       }
-       else
-               m::recorder::rec(ch->index, type, frame_a);
-
-       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void recordEnvelopeAction(Channel* ch, int type, int frame, float fValue)
+void updateChannel(geChannel* gch, bool refreshActionEditor)
 {
-       namespace mr = m::recorder;
-
-       if (!mr::hasActions(ch->index, type)) {  // First action ever? Add actions at boundaries.
-               mr::rec(ch->index, type, 0, 0, 1.0);    
-               mr::rec(ch->index, type, m::clock::getFramesInLoop() - 1, 0, 1.0);      
-       }
-       mr::rec(ch->index, type, frame, 0, fValue);
-
-       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void deleteEnvelopeAction(Channel* ch, m::recorder::action a, bool moved)
-{
-       namespace mr = m::recorder;
-
-       /* Deleting first or last action: clear everything. Otherwise delete the 
-       selected action only. */
-
-       if (!moved && (a.frame == 0 || a.frame == m::clock::getFramesInLoop() - 1))
-               mr::clearAction(ch->index, a.type);
-       else
-               mr::deleteAction(ch->index, a.frame, a.type, false, &m::mixer::mutex);
-
-       updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void deleteSampleAction(SampleChannel* ch, m::recorder::action a1, 
-       m::recorder::action a2)
-{
-       namespace mr = m::recorder;
-
-       /* if SINGLE_PRESS delete both the keypress and the keyrelease pair. */
-
-       if (ch->mode == ChannelMode::SINGLE_PRESS) {
-               mr::deleteAction(ch->index, a1.frame, G_ACTION_KEYPRESS, false, &m::mixer::mutex);
-               mr::deleteAction(ch->index, a2.frame, G_ACTION_KEYREL, false, &m::mixer::mutex);
-       }
-       else
-               mr::deleteAction(ch->index, a1.frame, a1.type, false, &m::mixer::mutex);
-
-  updateChannel(ch->guiChannel, /*refreshActionEditor=*/false);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-vector<m::recorder::Composite> getSampleActions(const SampleChannel* ch)
-{
-       namespace mr = m::recorder;
-
-       vector<mr::Composite> out;
-
-       mr::sortActions();
-       mr::forEachAction([&](const mr::action* a1)
-       {
-               /* Exclude:
-               - actions beyond clock::getFramesInLoop();
-               - actions that don't belong to channel ch;
-               - actions != G_ACTION_KEYPRESS, G_ACTION_KEYREL or G_ACTION_KILL;
-               - G_ACTION_KEYREL actions in a SINGLE_PRESS context. */
-
-               if (a1->frame > m::clock::getFramesInLoop() || 
-                         a1->chan != ch->index                   || 
-                         a1->type & ~(G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL) || 
-                         (ch->mode == ChannelMode::SINGLE_PRESS && a1->type == G_ACTION_KEYREL))
-                       return;
-
-               mr::Composite cmp; 
-               cmp.a1 = *a1;
-               cmp.a2.frame = -1;
-
-               /* If SINGLE_PRESS mode and the current action is G_ACTION_KEYPRESS, let's
-               fetch the corresponding G_ACTION_KEYREL. */
-
-               if (ch->mode == ChannelMode::SINGLE_PRESS && a1->type == G_ACTION_KEYPRESS) {
-                       m::recorder::action* a2 = nullptr;
-                       mr::getNextAction(ch->index, G_ACTION_KEYREL, a1->frame, &a2);
-                       if (a2 != nullptr)
-                               cmp.a2 = *a2;
-               }
-
-               out.push_back(cmp);
-       });
-
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-vector<m::recorder::action> getEnvelopeActions(const Channel* ch, int type)
-{
-       namespace mr = m::recorder;
-
-       vector<mr::action> out;
-
-       mr::sortActions();
-       mr::forEachAction([&](const mr::action* a)
-       {
-               /* Exclude:
-               - actions beyond clock::getFramesInLoop();
-               - actions that don't belong to channel ch;
-               - actions with wrong type. */
-
-               if (a->frame > m::clock::getFramesInLoop() || 
-                         a->chan != ch->index                   || 
-                         a->type != type)
-                       return;
-
-               out.push_back(*a);
-       });
-
-       return out;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void setVelocity(const Channel* ch, m::recorder::action a, int value)
-{
-       /* TODO - this is super ugly: delete the action and add a new one with the
-       modified values. This shit will go away as soon as we'll refactor m::recorder
-       for good. */
-
-       m::MidiEvent event = m::MidiEvent(a.iValue);
-       event.setVelocity(value);
-
-       m::recorder::deleteAction(ch->index, a.frame, G_ACTION_MIDI, true, 
-               &m::mixer::mutex, a.iValue, 0.0);
-       m::recorder::rec(ch->index, G_ACTION_MIDI, a.frame, event.getRaw());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-vector<m::recorder::Composite> getMidiActions(int chan)
-{
-       vector<m::recorder::Composite> out;
-
-       m::recorder::sortActions();
-
-       for (unsigned i=0; i<m::recorder::frames.size(); i++) {
-
-               if (m::recorder::frames.at(i) > m::clock::getFramesInLoop())
-                       continue;
-
-               for (unsigned j=0; j<m::recorder::global.at(i).size(); j++) {
-
-                       m::recorder::action* a1 = m::recorder::global.at(i).at(j);
-                       m::recorder::action* a2 = nullptr;
-
-                       m::MidiEvent a1midi(a1->iValue);
-
-                       /* Skip action if:
-                               - does not belong to this channel
-                               - is not a MIDI action (we only want MIDI things here)
-                               - is not a MIDI Note On type. We don't want any other kind of action here */
-
-                       if (a1->chan != chan || a1->type != G_ACTION_MIDI || 
-                                 a1midi.getStatus() != m::MidiEvent::NOTE_ON)
-                               continue;
-
-                       /* Prepare the composite action. Action 1 exists for sure, so fill it up
-                       right away. */
-
-                       m::recorder::Composite cmp; 
-                       cmp.a1 = *a1;
-
-                       /* Search for the next action. Must have: same channel, G_ACTION_MIDI,
-                       greater than a1->frame and with MIDI properties of note_off (0x80), same
-                       note of a1 and random velocity: we don't care about it (and so we mask it
-                       with 0x0000FF00). */
-
-                       m::recorder::getNextAction(chan, G_ACTION_MIDI, a1->frame, &a2, 
-                               m::MidiEvent(m::MidiEvent::NOTE_OFF, a1midi.getNote(), 0x0).getRaw(), 
-                               0x0000FF00);
-
-                       /* If action 2 has been found, add it to the composite duo. Otherwise
-                       set the action 2 frame to -1: it should be intended as "orphaned". */
-
-                       if (a2 != nullptr)
-                               cmp.a2 = *a2;
-                       else
-                               cmp.a2.frame = -1;
-
-                       out.push_back(cmp);
-               }
+       gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
+       if (gch->ch->type == ChannelType::SAMPLE) {
+               geSampleChannel* gsch = static_cast<geSampleChannel*>(gch);
+               gsch->ch->hasActions ? gsch->showActionButton() : gsch->hideActionButton();
        }
-
-       return out;
+       if (refreshActionEditor)
+               gu_refreshActionEditor(); // refresh a.editor window, it could be open
 }
 
 }}} // giada::c::recorder::
\ No newline at end of file
index 1bf4a4044feb4045d9fe5cf3fec9a14327ebec9e..f28a3ccd00c8a1703ae94f035cc91f29ed3b1c28 100644 (file)
 #define G_GLUE_RECORDER_H
 
 
-#include <vector>
-#include "../core/recorder.h"
-
-
-class SampleChannel;
-class MidiChannel;
 class geChannel;
 
 
 namespace giada {
-namespace c     {
+namespace c {
 namespace recorder 
 {
 void clearAllActions(geChannel* gch);
 void clearVolumeActions(geChannel* gch);
 void clearStartStopActions(geChannel* gch);
-
-
-
-/* MOVE ALL THESE FUNCTIONS TO c::actionEditor*/
-
-
-bool midiActionCanFit(int chan, int note, int frame_a, int frame_b);
-bool sampleActionCanFit(const SampleChannel* ch, int frame_a, int frame_b);
-
-/* recordMidiAction
-Records a new MIDI action at frame_a. If frame_b == 0, uses the default action
-size. This function is designed for the Piano Roll (not for live recording). */
-
-void recordMidiAction(int chan, int note, int velocity, int frame_a, int frame_b=0);
-
-void recordEnvelopeAction(Channel* ch, int type, int frame, float fValue);
-
-void recordSampleAction(SampleChannel* ch, int type, int frame_a, int frame_b=0);
-
-void setVelocity(const Channel* ch, m::recorder::action a, int value);
-
-/* getMidiActions
-Returns a list of Composite actions, ready to be displayed in a MIDI note
-editor as pairs of NoteOn+NoteOff. */
-
-std::vector<m::recorder::Composite> getMidiActions(int channel);
-
-std::vector<m::recorder::action> getEnvelopeActions(const Channel* ch, int type);
-
-/* getSampleActions
-Returns a list of Composite actions, ready to be displayed in a Sample Action
-Editor. If actions are not keypress+keyrelease combos, the second action in
-the Composite struct if left empty (with action2.frame = -1). */
-
-std::vector<m::recorder::Composite> getSampleActions(const SampleChannel* ch);
-
-void deleteMidiAction(MidiChannel* ch, m::recorder::action a1, m::recorder::action a2);
-
-void deleteSampleAction(SampleChannel* ch, m::recorder::action a1, 
-       m::recorder::action a2);
-
-void deleteEnvelopeAction(Channel* ch, m::recorder::action a, bool moved);
-
+void updateChannel(geChannel* gch, bool refreshActionEditor=true);
 }}} // giada::c::recorder::
 
 #endif
index 1793a92d5e57364f4155f808605c013a5f65fde8..f86c67bfa19abdba105059ff4b0b49f90096f352 100644 (file)
@@ -51,7 +51,7 @@
 #include "sampleEditor.h"
 
 
-extern gdMainWindow *G_MainWin;
+extern gdMainWindowG_MainWin;
 
 
 namespace giada {
@@ -81,7 +81,7 @@ gdSampleEditor* getSampleEditorWindow()
 /* -------------------------------------------------------------------------- */
 
 
-void setBeginEnd(SampleChannel* ch, int b, int e)
+void setBeginEnd(m::SampleChannel* ch, int b, int e)
 {
        ch->setBegin(b);
        ch->setEnd(e);
@@ -99,7 +99,7 @@ void setBeginEnd(SampleChannel* ch, int b, int e)
 /* -------------------------------------------------------------------------- */
 
 
-void cut(SampleChannel* ch, int a, int b)
+void cut(m::SampleChannel* ch, int a, int b)
 {
        copy(ch, a, b);
        if (!m::wfx::cut(*ch->wave, a, b)) {
@@ -117,7 +117,7 @@ void cut(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void copy(SampleChannel* ch, int a, int b)
+void copy(m::SampleChannel* ch, int a, int b)
 {
        if (m_waveBuffer != nullptr)
                delete m_waveBuffer;
@@ -128,7 +128,7 @@ void copy(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void paste(SampleChannel* ch, int a)
+void paste(m::SampleChannel* ch, int a)
 {
        if (!isWaveBufferFull()) {
                gu_log("[sampleEditor::paste] Buffer is empty, nothing to paste\n");
@@ -155,7 +155,7 @@ void paste(SampleChannel* ch, int a)
 /* -------------------------------------------------------------------------- */
 
 
-void silence(SampleChannel* ch, int a, int b)
+void silence(m::SampleChannel* ch, int a, int b)
 {
        m::wfx::silence(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -166,7 +166,7 @@ void silence(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void fade(SampleChannel* ch, int a, int b, int type)
+void fade(m::SampleChannel* ch, int a, int b, int type)
 {
        m::wfx::fade(*ch->wave, a, b, type);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -177,7 +177,7 @@ void fade(SampleChannel* ch, int a, int b, int type)
 /* -------------------------------------------------------------------------- */
 
 
-void smoothEdges(SampleChannel* ch, int a, int b)
+void smoothEdges(m::SampleChannel* ch, int a, int b)
 {
        m::wfx::smooth(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -188,7 +188,7 @@ void smoothEdges(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void reverse(SampleChannel* ch, int a, int b)
+void reverse(m::SampleChannel* ch, int a, int b)
 {
        m::wfx::reverse(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -199,7 +199,7 @@ void reverse(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void normalizeHard(SampleChannel* ch, int a, int b)
+void normalizeHard(m::SampleChannel* ch, int a, int b)
 {
        m::wfx::normalizeHard(*ch->wave, a, b);
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -210,7 +210,7 @@ void normalizeHard(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void trim(SampleChannel* ch, int a, int b)
+void trim(m::SampleChannel* ch, int a, int b)
 {
        if (!m::wfx::trim(*ch->wave, a, b)) {
                gdAlert("Unable to trim the sample!");
@@ -227,7 +227,7 @@ void trim(SampleChannel* ch, int a, int b)
 /* -------------------------------------------------------------------------- */
 
 
-void setPlayHead(SampleChannel* ch, int f)
+void setPlayHead(m::SampleChannel* ch, int f)
 {
        ch->trackerPreview = f;
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -238,7 +238,7 @@ void setPlayHead(SampleChannel* ch, int f)
 /* -------------------------------------------------------------------------- */
 
 
-void setPreview(SampleChannel* ch, PreviewMode mode)
+void setPreview(m::SampleChannel* ch, PreviewMode mode)
 {
        ch->previewMode = mode;
        gdSampleEditor* gdEditor = getSampleEditorWindow();
@@ -249,7 +249,7 @@ void setPreview(SampleChannel* ch, PreviewMode mode)
 /* -------------------------------------------------------------------------- */
 
 
-void rewindPreview(SampleChannel* ch)
+void rewindPreview(m::SampleChannel* ch)
 {
        geWaveform* waveform = getSampleEditorWindow()->waveTools->waveform;
        if (waveform->isSelected() && ch->trackerPreview != waveform->getSelectionA())
@@ -262,9 +262,9 @@ void rewindPreview(SampleChannel* ch)
 /* -------------------------------------------------------------------------- */
 
 
-void toNewChannel(SampleChannel* ch, int a, int b)
+void toNewChannel(m::SampleChannel* ch, int a, int b)
 {
-       SampleChannel* newCh = static_cast<SampleChannel*>(c::channel::addChannel(
+       m::SampleChannel* newCh = static_cast<m::SampleChannel*>(c::channel::addChannel(
                ch->guiChannel->getColumnIndex(), ChannelType::SAMPLE, G_GUI_CHANNEL_H_1));
 
        Wave* wave = nullptr;
@@ -287,7 +287,7 @@ bool isWaveBufferFull()
 /* -------------------------------------------------------------------------- */
 
 
-void shift(SampleChannel* ch, int offset)
+void shift(m::SampleChannel* ch, int offset)
 {
        m::wfx::shift(*ch->wave, offset - ch->shift);
        ch->shift = offset;
index 4933100486f7fe8081a3b1b5b0e1c3056b0d32d4..3cd4bc87316f2c2d7686c0d1592a8337693dea78 100644 (file)
 #include "../core/types.h"
 
 
-class SampleChannel;
 class geWaveform;
 
 
 namespace giada {
-namespace c     {
+namespace m
+{
+class SampleChannel;
+}
+namespace c {
 namespace sampleEditor 
 {
 /* setBeginEnd
 Sets start/end points in the sample editor. */
 
-void setBeginEnd(SampleChannel* ch, int b, int e);
+void setBeginEnd(m::SampleChannel* ch, int b, int e);
 
-void cut(SampleChannel* ch, int a, int b);
-void copy(SampleChannel* ch, int a, int b);
+void cut(m::SampleChannel* ch, int a, int b);
+void copy(m::SampleChannel* ch, int a, int b);
 
 /* paste
 Pastes what's defined in m_copyBuffer into channel 'ch' at point 'a'. If 
 m_copyBuffer is empty, does nothing. */
 
-void paste(SampleChannel* ch, int a);
+void paste(m::SampleChannel* ch, int a);
 
-void trim(SampleChannel* ch, int a, int b);
-void reverse(SampleChannel* ch, int a, int b);
-void normalizeHard(SampleChannel* ch, int a, int b);
-void silence(SampleChannel* ch, int a, int b);
-void fade(SampleChannel* ch, int a, int b, int type);
-void smoothEdges(SampleChannel* ch, int a, int b);
-void shift(SampleChannel* ch, int offset);
+void trim(m::SampleChannel* ch, int a, int b);
+void reverse(m::SampleChannel* ch, int a, int b);
+void normalizeHard(m::SampleChannel* ch, int a, int b);
+void silence(m::SampleChannel* ch, int a, int b);
+void fade(m::SampleChannel* ch, int a, int b, int type);
+void smoothEdges(m::SampleChannel* ch, int a, int b);
+void shift(m::SampleChannel* ch, int offset);
 
 bool isWaveBufferFull();
 
 /* setPlayHead
 Changes playhead's position. Used in preview. */
 
-void setPlayHead(SampleChannel* ch, int f);
+void setPlayHead(m::SampleChannel* ch, int f);
 
-void setPreview(SampleChannel* ch, PreviewMode mode);
-void rewindPreview(SampleChannel* ch);
+void setPreview(m::SampleChannel* ch, PreviewMode mode);
+void rewindPreview(m::SampleChannel* ch);
 
 /* toNewChannel
 Copies the selected range into a new sample channel. */
 
-void toNewChannel(SampleChannel* ch, int a, int b);
+void toNewChannel(m::SampleChannel* ch, int a, int b);
 }}}; // giada::c::sampleEditor::
 
 #endif
index 2a79efc797f99ee25f07c8976bdd605d3ce12a63..e3779e2d5548c4aca515b925812eead5234c78b7 100644 (file)
@@ -28,6 +28,7 @@
 #include "../core/mixer.h"
 #include "../core/mixerHandler.h"
 #include "../core/channel.h"
+#include "../core/recorderHandler.h"
 #include "../core/pluginHost.h"
 #include "../core/plugin.h"
 #include "../core/conf.h"
@@ -63,7 +64,7 @@ using namespace giada;
 
 #ifdef WITH_VST
 
-static void glue_fillPatchGlobalsPlugins__(vector <Plugin*>* host, vector<m::patch::plugin_t>* patch)
+static void glue_fillPatchGlobalsPlugins__(vector <m::Plugin*>* host, vector<m::patch::plugin_t>* patch)
 {
        using namespace giada::m;
 
@@ -90,14 +91,13 @@ static void glue_fillPatchColumns__()
        using namespace giada::m;
 
        for (unsigned i=0; i<G_MainWin->keyboard->getTotalColumns(); i++) {
-               geColumn *gCol = G_MainWin->keyboard->getColumn(i);
+               geColumngCol = G_MainWin->keyboard->getColumn(i);
                patch::column_t pCol;
                pCol.index = gCol->getIndex();
                pCol.width = gCol->w();
                for (int k=0; k<gCol->countChannels(); k++) {
-                       Channel *colChannel = gCol->getChannel(k);
-                       for (unsigned j=0; j<mixer::channels.size(); j++) {
-                               Channel *mixerChannel = mixer::channels.at(j);
+                       Channel* colChannel = gCol->getChannel(k);
+                       for (const Channel* mixerChannel : mixer::channels) {
                                if (colChannel == mixerChannel) {
                                        pCol.channels.push_back(mixerChannel->index);
                                        break;
@@ -185,7 +185,7 @@ static string glue_makeSamplePath__(const string& base, const Wave* w, int k)
 } 
 
 
-static string glue_makeUniqueSamplePath__(const string& base, const SampleChannel* ch)
+static string glue_makeUniqueSamplePath__(const string& base, const m::SampleChannel* ch)
 {
        using namespace giada::m;
 
@@ -261,7 +261,7 @@ void glue_loadPatch(void* data)
                return;
        }
 
-       /* Close all other windows. This prevents segfault if plugin windows GUIs are 
+       /* Close all other windows. This prevents problems if plugin windows are 
        open. */
 
        gu_closeAllSubwindows();
@@ -274,32 +274,27 @@ void glue_loadPatch(void* data)
        browser->setStatusBar(0.1f);
 
        /* Add common stuff, columns and channels. Also increment the progress bar by 
-       0.8 / total_channels steps.  */
+       0.8 / total_channels steps. */
 
        float steps = 0.8 / patch::channels.size();
        
        for (const patch::column_t& col : patch::columns) {
                G_MainWin->keyboard->addColumn(col.width);
-               unsigned k = 0;
                for (const patch::channel_t& pch : patch::channels) {
                        if (pch.column == col.index) {
                                Channel* ch = c::channel::addChannel(pch.column, static_cast<ChannelType>(pch.type), pch.size);
-                               ch->readPatch(basePath, k);
+                               ch->readPatch(basePath, pch);
                        }
                        browser->setStatusBar(steps);
-                       k++;
                }
        }
 
-       /* Prepare Mixer. */
+       /* Prepare Mixer and Recorder. The latter has to recompute the actions' 
+       positions if the current samplerate != patch samplerate.*/
 
        mh::updateSoloCount();
        mh::readPatch();
-
-       /* Let recorder recompute the actions' positions if the current 
-       samplerate != patch samplerate. */
-
-       recorder::updateSamplerate(conf::samplerate, patch::samplerate);
+       recorderHandler::updateSamplerate(conf::samplerate, patch::samplerate);
 
        /* Save patchPath by taking the last dir of the broswer, in order to reuse it 
        the next time. */
@@ -394,7 +389,7 @@ void glue_loadSample(void* data)
        if (fullPath.empty())
                return;
 
-       int res = c::channel::loadChannel(static_cast<SampleChannel*>(browser->getChannel()), 
+       int res = c::channel::loadChannel(static_cast<m::SampleChannel*>(browser->getChannel()), 
                fullPath);
 
        if (res == G_RES_OK) {
index 9a3e568b0d17587897ec00ef96ed5c0f22f3cf4e..35f15d2fbbd9822f0be7e84a7682ae40d6fa51b2 100644 (file)
 #define G_GLUE_STORAGE_H
 
 
-void glue_loadPatch  (void *data);
-void glue_savePatch  (void *data);
-void glue_saveProject(void *data);
-void glue_saveSample (void *data);
-void glue_loadSample (void *data);
+void glue_loadPatch  (voiddata);
+void glue_savePatch  (voiddata);
+void glue_saveProject(voiddata);
+void glue_saveSample (voiddata);
+void glue_loadSample (voiddata);
 
 
 #endif
index f735f7e071f280f5090a1b03d738388328932b9d..4e958dce94b4dfd8483ce48bb6cf964864bfee5d 100644 (file)
 #include "../gui/elems/mainWindow/mainTransport.h"
 #include "../gui/dialogs/gd_mainWindow.h"
 #include "../core/clock.h"
+#include "../core/conf.h"
+#include "../core/const.h"
 #include "../core/kernelAudio.h"
+#include "../core/kernelMidi.h"
 #include "../core/mixerHandler.h"
 #include "../core/mixer.h"
 #include "../core/recorder.h"
 #include "transport.h"
 
 
-extern gdMainWindow *G_MainWin;
-
+extern gdMainWindowG_MainWin;
 
 using namespace giada::m;
 
 
-void glue_startStopSeq(bool gui)
+namespace giada {
+namespace c {
+namespace transport 
+{
+void startStopSeq(bool gui)
 {
-       clock::isRunning() ? glue_stopSeq(gui) : glue_startSeq(gui);
+       clock::isRunning() ? stopSeq(gui) : startSeq(gui);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void glue_startSeq(bool gui)
+void startSeq(bool gui)
 {
        clock::start();
 
@@ -60,9 +67,9 @@ void glue_startSeq(bool gui)
 #endif
 
        if (!gui) {
-    Fl::lock();
-    G_MainWin->mainTransport->updatePlay(1);
-    Fl::unlock();
+               Fl::lock();
+               G_MainWin->mainTransport->updatePlay(1);
+               Fl::unlock();
   }
 }
 
@@ -70,7 +77,7 @@ void glue_startSeq(bool gui)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_stopSeq(bool gui)
+void stopSeq(bool gui)
 {
        mh::stopSequencer();
 
@@ -78,38 +85,58 @@ void glue_stopSeq(bool 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 */
+       /* 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;
-    Fl::lock();
-         G_MainWin->mainTransport->updateRecAction(0);
-         Fl::unlock();
+       if (recorder::isActive()) {
+               recorder::disable();
+               Fl::lock();
+               G_MainWin->mainTransport->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 input recs are active (who knows why) we must deactivate them. One 
+       might stop the sequencer while an input rec is running. */
 
        if (mixer::recording) {
                mh::stopInputRec();
-    Fl::lock();
-         G_MainWin->mainTransport->updateRecInput(0);
-         Fl::unlock();
+               Fl::lock();
+               G_MainWin->mainTransport->updateRecInput(0);
+               Fl::unlock();
        }
 
        if (!gui) {
-    Fl::lock();
-         G_MainWin->mainTransport->updatePlay(0);
-         Fl::unlock();
-  }
+               Fl::lock();
+               G_MainWin->mainTransport->updatePlay(0);
+               Fl::unlock();
+       }
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void glue_startStopMetronome(bool gui)
+void rewindSeq(bool gui, bool notifyJack)
+{
+       mh::rewindSequencer();
+
+       /* FIXME - potential desync when Quantizer is enabled from this point on.
+       Mixer would wait, while the following calls would be made regardless of its
+       state. */
+
+#ifdef __linux__
+       if (notifyJack)
+               kernelAudio::jackSetPosition(0);
+#endif
+
+       if (conf::midiSync == MIDI_SYNC_CLOCK_M)
+               kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void startStopMetronome(bool gui)
 {
        mixer::metronome = !mixer::metronome;
        if (!gui) {
@@ -118,3 +145,5 @@ void glue_startStopMetronome(bool gui)
                Fl::unlock();
        }
 }
+
+}}} // giada::c::transport::
\ No newline at end of file
index 3b10eadede49e6f2ea3d21b3bca44e8b36369c29..3be492fd50e85a414392753b6744b78bead2ced9 100644 (file)
 #define G_GLUE_TRANSPORT_H
 
 
-/* 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(bool gui=true, bool notifyJack=true);
-void glue_startStopMetronome(bool gui=true);
+namespace giada {
+namespace c {
+namespace transport 
+{
+void startStopSeq(bool gui=true);
+void startSeq(bool gui=true);
+void stopSeq(bool gui=true);
+void rewindSeq(bool gui=true, bool notifyJack=true);
+void startStopMetronome(bool gui=true);
+}}} // giada::c::transport::
 
 
 #endif
index b85a30e815310326a4deaafec3b98651ce08ec90..c7fc692d66946e567f89cbac3ccf385f48149ef5 100644 (file)
@@ -47,7 +47,7 @@ using std::string;
 namespace giada {
 namespace v
 {
-gdBaseActionEditor::gdBaseActionEditor(Channel* ch)
+gdBaseActionEditor::gdBaseActionEditor(m::Channel* ch)
 :      gdWindow (640, 284),
        ch       (ch),
        ratio    (G_DEFAULT_ZOOM_RATIO)
@@ -86,6 +86,15 @@ void gdBaseActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdBaseActionEdito
 /* -------------------------------------------------------------------------- */
 
 
+const std::vector<const m::Action*>& gdBaseActionEditor::getActions()
+{
+       return m_actions;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void gdBaseActionEditor::computeWidth()
 {
        fullWidth = frameToPixel(m::clock::getFramesInSeq());
@@ -113,14 +122,17 @@ Frame gdBaseActionEditor::pixelToFrame(Pixel p, bool snap) const
 
 void gdBaseActionEditor::zoomIn()
 {
-       if (ratio / 2 > MIN_RATIO) {
-               ratio /= 2;
+       float ratioPrev = ratio;
+
+       ratio /= 2;
+       if (ratio < MIN_RATIO)
+               ratio = MIN_RATIO;
+
+       if (ratioPrev != ratio) {
                rebuild();
                centerViewportIn();
                redraw();
        }
-       else
-               ratio = MIN_RATIO;
 }
 
 
@@ -129,14 +141,17 @@ void gdBaseActionEditor::zoomIn()
 
 void gdBaseActionEditor::zoomOut()
 {
-       if (ratio * 2 < MAX_RATIO) {
-               ratio *= 2;
+       float ratioPrev = ratio;
+       
+       ratio *= 2;
+       if (ratio > MAX_RATIO)
+               ratio = MAX_RATIO;
+
+       if (ratioPrev != ratio) {
                rebuild();
                centerViewportOut();
                redraw();
        }
-       else
-               ratio = MAX_RATIO;
 }
 
 
@@ -164,13 +179,13 @@ void gdBaseActionEditor::centerViewportOut()
 int gdBaseActionEditor::getActionType() const
 {
        if (actionType->value() == 0)
-               return G_ACTION_KEYPRESS;
+               return m::MidiEvent::NOTE_ON;
        else
        if (actionType->value() == 1)
-               return G_ACTION_KEYREL;
+               return m::MidiEvent::NOTE_OFF;
        else
        if (actionType->value() == 2)
-               return G_ACTION_KILL;
+               return m::MidiEvent::NOTE_KILL;
 
        assert(false);
        return -1;
index 1b35d79dd48a31f21f044e5f5ca45ee3c52310b6..da7ce46cd783ab59c9571e12f76c3ac7e87d0ba3 100644 (file)
 #include "../window.h"
 
 
-class Channel;
 class geChoice;
 class geButton;
 class geScroll;
 
 
 namespace giada {
+namespace m
+{
+class Channel;
+class Action;
+}
 namespace v
 {
 class geGridTool;
@@ -54,7 +58,9 @@ protected:
        static constexpr float MIN_RATIO     = 25.0f;
        static constexpr float MAX_RATIO     = 40000.0f;
 
-       gdBaseActionEditor(Channel* ch);
+       std::vector<const m::Action*> m_actions;
+
+       gdBaseActionEditor(m::Channel* ch);
 
        void zoomIn();
        void zoomOut();
@@ -87,16 +93,18 @@ public:
        Frame pixelToFrame(Pixel p, bool snap=true) const;
        int getActionType() const;
 
+       const std::vector<const m::Action*>& getActions();
+
        geChoice*   actionType;
        geGridTool* gridTool;
        geButton*   zoomInBtn;
        geButton*   zoomOutBtn;
        geScroll*   viewport;       // widget container
 
-       Channel* ch;
+       m::Channel* ch;
 
        float ratio;
-       Pixel fullWidth;   // Full widgets width, i.e. scaled-down full sequencer
+       Pixel fullWidth;     // Full widgets width, i.e. scaled-down full sequencer
        Pixel loopWidth;         // Loop width, i.e. scaled-down sequencer range
 };
 }} // giada::v::
index ab65cef8a8624f6e62c83c3affa7fbbb7ebabbcd..28bd61a05adeda2e49064578455519c33b85bd6b 100644 (file)
@@ -28,6 +28,7 @@
 #include <string>
 #include "../../../core/graphics.h"
 #include "../../../core/midiChannel.h"
+#include "../../../glue/actionEditor.h"
 #include "../../elems/basics/scroll.h"
 #include "../../elems/basics/button.h"
 #include "../../elems/basics/resizerBar.h"
@@ -45,7 +46,7 @@ using std::string;
 namespace giada {
 namespace v
 {
-gdMidiActionEditor::gdMidiActionEditor(MidiChannel* ch)
+gdMidiActionEditor::gdMidiActionEditor(m::MidiChannel* ch)
 : gdBaseActionEditor(ch)
 {
        computeWidth();
@@ -70,16 +71,19 @@ gdMidiActionEditor::gdMidiActionEditor(MidiChannel* ch)
 
        viewport = new geScroll(8, 36, w()-16, h()-44);
 
-       ne = new geNoteEditor(viewport->x(), viewport->y(), this);
-       viewport->add(ne);
-       viewport->add(new geResizerBar(ne->x(), ne->y()+ne->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       m_ne  = new geNoteEditor(viewport->x(), viewport->y(), this);
+       m_ner = new geResizerBar(m_ne->x(), m_ne->y()+m_ne->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H);
+       viewport->add(m_ne);
+       viewport->add(m_ner);
        
-       ve = new geVelocityEditor(viewport->x(), ne->y()+ne->h()+RESIZER_BAR_H, ch);
-       viewport->add(ve);
-       viewport->add(new geResizerBar(ve->x(), ve->y()+ve->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       m_ve  = new geVelocityEditor(viewport->x(), m_ne->y()+m_ne->h()+RESIZER_BAR_H, ch);
+       m_ver = new geResizerBar(m_ve->x(), m_ve->y()+m_ve->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H);
+       viewport->add(m_ve);
+       viewport->add(m_ver);
 
        end();
        prepareWindow();
+       rebuild();
 }
 
 
@@ -88,8 +92,11 @@ gdMidiActionEditor::gdMidiActionEditor(MidiChannel* ch)
 
 void gdMidiActionEditor::rebuild()
 {
+       m_actions = c::actionEditor::getActions(ch);
        computeWidth();
-       ne->rebuild();
-       ve->rebuild();
+       m_ne->rebuild();
+       m_ner->size(m_ne->w(), m_ner->h());
+       m_ve->rebuild();
+       m_ver->size(m_ve->w(), m_ver->h());
 }
 }} // giada::v::
index 15da033982311d797ef20b99cf5183013d8c6c10..f850099f819243b80e1aeefac4f61d4e7d67dee8 100644 (file)
@@ -32,7 +32,7 @@
 #include "baseActionEditor.h"
 
 
-class MidiChannel;
+class geResizerBar;
 
 
 namespace giada {
@@ -46,12 +46,15 @@ class gdMidiActionEditor : public gdBaseActionEditor
 {
 private:
 
-       geNoteEditor*     ne;
-       geVelocityEditor* ve;
+    geNoteEditor*     m_ne;
+       geResizerBar*     m_ner;
+
+       geVelocityEditor* m_ve;
+    geResizerBar*     m_ver;
 
 public:
 
-       gdMidiActionEditor(MidiChannel* ch);
+       gdMidiActionEditor(m::MidiChannel* ch);
 
        void rebuild() override;
 };
index 2f2e268d12e7dd47d1f902f1814380cf0b2cbd0f..e69a89cbd78da325e0e9db6f7b01db39bf2c7007 100644 (file)
 
 #include <string>
 #include "../../../core/const.h"
+#include "../../../core/midiEvent.h"
 #include "../../../core/graphics.h"
 #include "../../../core/sampleChannel.h"
+#include "../../../glue/actionEditor.h"
 #include "../../elems/basics/scroll.h"
 #include "../../elems/basics/button.h"
 #include "../../elems/basics/resizerBar.h"
@@ -46,7 +48,7 @@ using std::string;
 namespace giada {
 namespace v
 {
-gdSampleActionEditor::gdSampleActionEditor(SampleChannel* ch)
+gdSampleActionEditor::gdSampleActionEditor(m::SampleChannel* ch)
 : gdBaseActionEditor(ch)
 {
        computeWidth();
@@ -82,16 +84,19 @@ gdSampleActionEditor::gdSampleActionEditor(SampleChannel* ch)
 
        viewport = new geScroll(8, 36, w()-16, h()-44);
 
-       ac = new geSampleActionEditor(viewport->x(), viewport->y(), ch);
-       viewport->add(ac);
-       viewport->add(new geResizerBar(ac->x(), ac->y()+ac->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       m_ae  = new geSampleActionEditor(viewport->x(), viewport->y(), ch);
+       m_aer = new geResizerBar(m_ae->x(), m_ae->y()+m_ae->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H);
+       viewport->add(m_ae);
+       viewport->add(m_aer);
        
-       vc = new geEnvelopeEditor(viewport->x(), ac->y()+ac->h()+RESIZER_BAR_H, G_ACTION_VOLUME, "volume", ch);
-       viewport->add(vc);
-       viewport->add(new geResizerBar(vc->x(), vc->y()+vc->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H));
+       m_ee  = new geEnvelopeEditor(viewport->x(), m_ae->y()+m_ae->h()+RESIZER_BAR_H, "volume", ch);
+       m_eer = new geResizerBar(m_ee->x(), m_ee->y()+m_ee->h(), viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H);
+       viewport->add(m_ee);
+       viewport->add(m_eer);
 
        end();
        prepareWindow();
+       rebuild();
 }
 
 
@@ -100,7 +105,7 @@ gdSampleActionEditor::gdSampleActionEditor(SampleChannel* ch)
 
 bool gdSampleActionEditor::canChangeActionType()
 {
-       SampleChannel* sch = static_cast<SampleChannel*>(ch); 
+       m::SampleChannel* sch = static_cast<m::SampleChannel*>(ch); 
        return sch->mode != ChannelMode::SINGLE_PRESS && !sch->isAnyLoopMode();
 }
 
@@ -110,9 +115,12 @@ bool gdSampleActionEditor::canChangeActionType()
 
 void gdSampleActionEditor::rebuild()
 {
+       m_actions = c::actionEditor::getActions(ch);
        canChangeActionType() ? actionType->activate() : actionType->deactivate(); 
        computeWidth();
-       ac->rebuild();
-       vc->rebuild();  
+       m_ae->rebuild();
+       m_aer->size(m_ae->w(), m_aer->h());
+       m_ee->rebuild();        
+       m_eer->size(m_ee->w(), m_eer->h());
 }
 }} // giada::v::
index 9832f216ababc90295186b25abb50f2f48292ee9..9d459a8baa9d66f057743be47117d28345d74a54 100644 (file)
 #include "baseActionEditor.h"
 
 
-class SampleChannel;
-class geSampleActionEditor;
-class geEnvelopeEditor;
+class geResizerBar;
 
 
 namespace giada {
 namespace v
 {
+class geSampleActionEditor;
+class geEnvelopeEditor;
+
 class gdSampleActionEditor : public gdBaseActionEditor
 {
 private:
 
-       geSampleActionEditor* ac;
-       geEnvelopeEditor*     vc;
+       geSampleActionEditor* m_ae;
+    geResizerBar*         m_aer;
+
+       geEnvelopeEditor*     m_ee;
+    geResizerBar*         m_eer;
 
        bool canChangeActionType();
        
 public:
 
-       gdSampleActionEditor(SampleChannel* ch);
+       gdSampleActionEditor(m::SampleChannel* ch);
 
        void rebuild() override;
 };
index 3f134bff7b215b6a1fb33597a46dde0f4765097d..710893bb215935671698425b5b5841f5f21e646b 100644 (file)
@@ -47,17 +47,16 @@ using namespace giada::m;
 
 
 gdBeatsInput::gdBeatsInput()
-       : gdWindow(180, 60, "Beats")
+       : gdWindow(180, 36, "Beats")
 {
        if (conf::beatsX)
                resize(conf::beatsX, conf::beatsY, w(), h());
 
        set_modal();
 
-       beats     = new geInput(8,  8,  43, G_GUI_UNIT);
-       bars      = new geInput(beats->x()+beats->w()+4, 8,  43, G_GUI_UNIT);
-       ok                  = new geButton(bars->x()+bars->w()+4, 8,  70, G_GUI_UNIT, "Ok");
-       resizeRec = new geCheck(8,  40, 12, 12, "resize recorded actions");
+       beats = new geInput(8,  8,  43, G_GUI_UNIT);
+       bars  = new geInput(beats->x()+beats->w()+4, 8,  43, G_GUI_UNIT);
+       ok        = new geButton(bars->x()+bars->w()+4, 8,  70, G_GUI_UNIT, "Ok");
        end();
 
        beats->maximum_size(2);
@@ -70,8 +69,6 @@ gdBeatsInput::gdBeatsInput()
        
        ok->shortcut(FL_Enter);
        ok->callback(cb_update, (void*)this);
-       
-       resizeRec->value(conf::resizeRecordings);
 
        gu_setFavicon(this);
        setId(WID_BEATS);
@@ -86,7 +83,6 @@ gdBeatsInput::~gdBeatsInput()
 {
        conf::beatsX = x();
        conf::beatsY = y();
-       conf::resizeRecordings = resizeRec->value();
 }
 
 
@@ -103,6 +99,6 @@ void gdBeatsInput::cb_update()
 {
        if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
                return;
-       glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value());
+       glue_setBeats(atoi(beats->value()), atoi(bars->value()));
        do_callback();
 }
index 938bd71319ae995d4ec2d7f2860b7a17fd3462eb..6b06da89f07535aac1045029e887a4ab789f1ea3 100644 (file)
@@ -47,7 +47,6 @@ private:
        geInput* beats;
        geInput* bars;
        geButton* ok;
-       geCheck* resizeRec;
 
 public:
 
index ccc2485ebf91c5a84967e0c2130177d655bb045f..883afdfd50f2cec62613003bb5badde98c52966b 100644 (file)
 
 
 #include "../window.h"
+#include "../../../core/plugin.h"
+#include "../../../core/channel.h"
 
 
 class Fl_Group;
-class Channel;
 class geCheck;
 class geBrowser;
 class geButton;
@@ -45,7 +46,7 @@ class gdBrowserBase : public gdWindow
 {
 protected:
 
-       Channel* channel;
+       giada::m::Channel* channel;
 
        Fl_Group* groupTop;
        geCheck* hiddenFiles;
@@ -81,7 +82,7 @@ public:
        std::string getSelectedItem() const;
 
        std::string getCurrentPath() const;
-       Channel* getChannel() const;
+       giada::m::Channel* getChannel() const;
        void fireCallback() const;
        
        /* setStatusBar
index 0c97065edacc6cc8601720e9336a725bdee7f34d..18f34b24f325118801dad6405c0e77b984a69441 100644 (file)
@@ -32,9 +32,6 @@
 #include "browserBase.h"
 
 
-class Channel;
-
-
 class gdBrowserDir : public gdBrowserBase
 {
 private:
index 266c4f3065e30803c8fca71854584903dd3a113e..a46c42e22eb775978d36c8d046ef3b652bc17d8b 100644 (file)
 
 
 using std::string;
+using namespace giada;
 
 
 gdBrowserLoad::gdBrowserLoad(int x, int y, int w, int h, const string& title,
-               const string& path, void (*cb)(void*), Channel* ch)
+               const string& path, void (*cb)(void*), m::Channel* ch)
        :       gdBrowserBase(x, y, w, h, title, path, cb)
 {
        channel = ch;
index e132a34ca0a2068ab5c0b367cfa579d2b0eb64af..9ef7d1823ad7ae38a9611005dfd623ef170dc750 100644 (file)
@@ -32,9 +32,6 @@
 #include "browserBase.h"
 
 
-class Channel;
-
-
 class gdBrowserLoad : public gdBrowserBase
 {
 private:
@@ -47,7 +44,7 @@ private:
 public:
 
        gdBrowserLoad(int x, int y, int w, int h, const std::string& title,
-                       const std::string& path, void (*callback)(void*), Channel* ch);
+                       const std::string& path, void (*callback)(void*), giada::m::Channel* ch);
 };
 
 
index b1559a8922df3ab93f4c26bf37621dd7ddfcbd5d..018b81b065ec81dfef58cfdd0cef08a762cac6e5 100644 (file)
@@ -33,6 +33,7 @@
 
 
 using std::string;
+using namespace giada::m;
 
 
 gdBrowserSave::gdBrowserSave(int x, int y, int w, int h, const string& title,
index acfa0d6f21eb4dad71a9f52992523630f0964327..867089c2c7ad0df29a0def9cdcbdf16042875629 100644 (file)
@@ -32,7 +32,6 @@
 #include "browserBase.h"
 
 
-class Channel;
 class geInput;
 
 
@@ -51,7 +50,7 @@ public:
 
        gdBrowserSave(int x, int y, int w, int h, const std::string& title,
                        const std::string& path, const std::string& name, void (*callback)(void*),
-                       Channel* ch);
+                       giada::m::Channel* ch);
 
        std::string getName() const;
 };
index 9380852ebf5681a16f97b1ae6de410c065596301..bca1a3556ad6262c22e6fcd920bf464dae9d2cca 100644 (file)
@@ -38,7 +38,7 @@
 using namespace giada;
 
 
-gdChannelNameInput::gdChannelNameInput(Channel* ch)
+gdChannelNameInput::gdChannelNameInput(m::Channel* ch)
 : gdWindow(400, 64, "New channel name"),
   m_ch    (ch)
 {
index 7e4a11365288c3829f01faab25a95ef2aebefb35..8f3214715830f40b6cc7acd3b1d2c2a09f016f9f 100644 (file)
@@ -32,7 +32,6 @@
 #include "window.h"
 
 
-class Channel;
 class geInput;
 class geButton;
 
@@ -46,7 +45,7 @@ private:
        void cb_update();
        void cb_cancel();
 
-       Channel* m_ch;
+       giada::m::Channel* m_ch;
 
        geInput* m_name;
        geButton* m_ok;
@@ -54,7 +53,7 @@ private:
 
 public:
 
-       gdChannelNameInput(Channel* ch);
+       gdChannelNameInput(giada::m::Channel* ch);
        ~gdChannelNameInput();
 };
 
index ea861b71e27d0fcb5310b61ae100d08d6397d1c6..418eb504884f606bbd93bdee19309f23c711c5d5 100644 (file)
@@ -45,9 +45,10 @@ extern gdMainWindow *mainWin;
 
 
 using std::string;
+using namespace giada;
 
 
-gdKeyGrabber::gdKeyGrabber(Channel *ch)
+gdKeyGrabber::gdKeyGrabber(m::Channel* ch)
        : gdWindow(300, 126, "Key configuration"), ch(ch)
 {
        set_modal();
@@ -69,14 +70,14 @@ gdKeyGrabber::gdKeyGrabber(Channel *ch)
 /* -------------------------------------------------------------------------- */
 
 
-void gdKeyGrabber::cb_clear (Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_clear(); }
-void gdKeyGrabber::cb_cancel(Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_cancel(); }
+void gdKeyGrabber::cb_clear (Fl_Widget* w, void* p) { ((gdKeyGrabber*)p)->cb_clear(); }
+void gdKeyGrabber::cb_cancel(Fl_Widget* w, void* p) { ((gdKeyGrabber*)p)->cb_cancel(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdKeyGrabber::__cb_cancel()
+void gdKeyGrabber::cb_cancel()
 {
        do_callback();
 }
@@ -85,7 +86,7 @@ void gdKeyGrabber::__cb_cancel()
 /* -------------------------------------------------------------------------- */
 
 
-void gdKeyGrabber::__cb_clear()
+void gdKeyGrabber::cb_clear()
 {
        updateText(0);
        setButtonLabel(0);
index d66a4034f2f3c0d5711b6431caecf3044c00f23c..92f2af1d1661941937b1b830a3a26d74f4d5823f 100644 (file)
@@ -33,7 +33,6 @@
 #include "window.h"
 
 
-class Channel;
 class geBox;
 class geButton;
 
@@ -42,23 +41,23 @@ class gdKeyGrabber : public gdWindow
 {
 private:
 
-       Channel *ch;
+       giada::m::Channel* ch;
 
-       geBox    *text;
-       geButton *clear;
-       geButton *cancel;
+       geBox*    text;
+       geButtonclear;
+       geButtoncancel;
 
-       static void cb_clear (Fl_Widget *w, void *p);
-       static void cb_cancel(Fl_Widget *w, void *p);
-       inline void __cb_clear ();
-       inline void __cb_cancel();
+       static void cb_clear (Fl_Widget* w, void* p);
+       static void cb_cancel(Fl_Widget* w, void* p);
+       void cb_clear ();
+       void cb_cancel();
 
        void setButtonLabel(int key);
        void updateText(int key);
 
 public:
 
-       gdKeyGrabber(Channel *ch);
+       gdKeyGrabber(giada::m::Channel* ch);
        int handle(int e);
 };
 
index d03714f075210833a5e0a64282bdabb0ea1006d0..cab1399eff633bb93cb4919d17d0bf4187a4a8b4 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <FL/Fl.H>
 #include "../../core/const.h"
+#include "../../core/conf.h"
 #include "../../core/init.h"
 #include "../../utils/gui.h"
 #include "../elems/basics/boxtypes.h"
 #include "gd_mainWindow.h"
 
 
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
+
+
+using namespace giada;
 
 
 gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** argv)
@@ -54,9 +58,9 @@ gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** arg
        Fl::set_boxtype(G_CUSTOM_UP_BOX,     g_customUpBox,     1, 1, 2, 2);
        Fl::set_boxtype(G_CUSTOM_DOWN_BOX,   g_customDownBox,   1, 1, 2, 2);
 
-  Fl::set_boxtype(FL_BORDER_BOX, G_CUSTOM_BORDER_BOX);
-  Fl::set_boxtype(FL_UP_BOX,     G_CUSTOM_UP_BOX);
-  Fl::set_boxtype(FL_DOWN_BOX,   G_CUSTOM_DOWN_BOX);
+       Fl::set_boxtype(FL_BORDER_BOX, G_CUSTOM_BORDER_BOX);
+       Fl::set_boxtype(FL_UP_BOX,     G_CUSTOM_UP_BOX);
+       Fl::set_boxtype(FL_DOWN_BOX,   G_CUSTOM_DOWN_BOX);
 
        size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
 
@@ -115,7 +119,12 @@ void gdMainWindow::cb_endprogram()
 {
        if (!gdConfirmWin("Warning", "Quit Giada: are you sure?"))
                return;
-       init_shutdown();
+
+       m::conf::mainWindowX = x();
+       m::conf::mainWindowY = y();
+       m::conf::mainWindowW = w();
+       m::conf::mainWindowH = h();
+
        hide();
        delete this;
 }
index 26e50bb56c6d021e2709a13dbcf3a35dc51160f1..3a06680cf3c6799f70bde96d5236a5e45f284559 100644 (file)
@@ -34,7 +34,6 @@
 #include "midiInputBase.h"
 
 
-class Channel;
 class geScroll;
 class geCheck;
 class geChoice;
@@ -44,7 +43,7 @@ class gdMidiInputChannel : public gdMidiInputBase
 {
 private:
 
-       Channel* ch;
+       giada::m::Channel* ch;
 
        geScroll* container;
        geCheck*  enable;
@@ -68,7 +67,7 @@ private:
 
 public:
 
-       gdMidiInputChannel(Channel* ch);
+       gdMidiInputChannel(giada::m::Channel* ch);
        ~gdMidiInputChannel();
 };
 
index ad425a5c7ee0a7c122ed22d062e38302a42bf325..1e19ad2958c03fe6c121fb05c88bb926cdfb45fa 100644 (file)
 #include "midiOutputMidiCh.h"
 
 
-gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel* ch)
+using namespace giada;
+
+
+gdMidiOutputMidiCh::gdMidiOutputMidiCh(m::MidiChannel* ch)
        : gdMidiOutputBase(300, 168), ch(ch)
 {
        setTitle(ch->index+1);
index 93fff1f21e5a41292df249ae196af072e4131277..b1fb4d87c792cd9f877f8975320cb4ad90ddc0b3 100644 (file)
@@ -50,11 +50,11 @@ private:
        class geCheck  *enableOut;
        class geChoice *chanListOut;
 
-       class MidiChannel *ch;
+       class giada::m::MidiChannel *ch;
 
 public:
 
-       gdMidiOutputMidiCh(class MidiChannel *ch);
+       gdMidiOutputMidiCh(class giada::m::MidiChannel *ch);
 };
 
 
index cd12d6ce66966c13e84ef8a929e5855daf2bc774..fdb21df2ce43b667163cfd75a9a1db18e25b9041 100644 (file)
 #include "midiOutputSampleCh.h"
 
 
-gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel* ch)
+using namespace giada;
+
+
+gdMidiOutputSampleCh::gdMidiOutputSampleCh(m::SampleChannel* ch)
        : gdMidiOutputBase(300, 140), ch(ch)
 {
        setTitle(ch->index+1);
index 7b679b1e094adea00eafa1f50b520844993ec868..fbd14eca1615699381bce2011206e892cc5428c2 100644 (file)
 #include "midiOutputBase.h"
 
 
-class SampleChannel;
-
-
 class gdMidiOutputSampleCh : public gdMidiOutputBase
 {
 private:
 
-       SampleChannel* ch;
+       giada::m::SampleChannel* ch;
 
        /* cb_close
        Override parent method, we need to do more stuff on close. */
@@ -49,7 +46,7 @@ private:
 
 public:
 
-       gdMidiOutputSampleCh(SampleChannel* ch);
+       gdMidiOutputSampleCh(giada::m::SampleChannel* ch);
 };
 
 #endif
index 21e5170b251843b5cd2bf2fa1ae563d791127221..361d735dd8a47d9d3dc958603add8d727889666f 100644 (file)
@@ -44,7 +44,7 @@ using namespace giada::m;
 using namespace giada::c;
 
 
-gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, int stackType, Channel *ch)
+gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, int stackType, Channelch)
   : gdWindow(X, Y, W, H, "Available plugins"), ch(ch), stackType(stackType)
 {
   /* top area */
@@ -99,15 +99,15 @@ gdPluginChooser::~gdPluginChooser()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginChooser::cb_close(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_close(); }
-void gdPluginChooser::cb_add(Fl_Widget *v, void *p)   { ((gdPluginChooser*)p)->__cb_add(); }
-void gdPluginChooser::cb_sort(Fl_Widget *v, void *p)  { ((gdPluginChooser*)p)->__cb_sort(); }
+void gdPluginChooser::cb_close(Fl_Widget* v, void* p) { ((gdPluginChooser*)p)->cb_close(); }
+void gdPluginChooser::cb_add(Fl_Widget* v, void* p)   { ((gdPluginChooser*)p)->cb_add(); }
+void gdPluginChooser::cb_sort(Fl_Widget* v, void* p)  { ((gdPluginChooser*)p)->cb_sort(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginChooser::__cb_close()
+void gdPluginChooser::cb_close()
 {
        do_callback();
 }
@@ -116,7 +116,7 @@ void gdPluginChooser::__cb_close()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginChooser::__cb_sort()
+void gdPluginChooser::cb_sort()
 {
        pluginHost::sortPlugins(sortMethod->value());
   browser->refresh();
@@ -126,7 +126,7 @@ void gdPluginChooser::__cb_sort()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginChooser::__cb_add()
+void gdPluginChooser::cb_add()
 {
   int index = browser->value() - 3; // subtract header lines
   if (index < 0)
index cd8f483cd3751800aa2f2c82cd1bd041cf2bfe40..53b3b14324c8df5031213a7cf246231fea9c61b3 100644 (file)
@@ -36,7 +36,6 @@
 #include "window.h"
 
 
-class Channel;
 class geChoice;
 class geButton;
 class geButton;
@@ -47,25 +46,25 @@ class gdPluginChooser : public gdWindow
 {
 private:
 
-  Channel *ch;      // ch == nullptr ? masterOut
+       giada::m::Channel* ch;      // ch == nullptr ? masterOut
        int stackType;
 
-  geChoice         *sortMethod;
-  geButton        *addBtn;
-  geButton        *cancelBtn;
-  gePluginBrowser *browser;
+       geChoice*        sortMethod;
+       geButton*        addBtn;
+       geButton*        cancelBtn;
+       gePluginBrowser* browser;
 
-       static void cb_close(Fl_Widget *w, void *p);
-       static void cb_add  (Fl_Widget *w, void *p);
-       static void cb_sort (Fl_Widget *w, void *p);
-  inline void __cb_close();
-  inline void __cb_add  ();
-  inline void __cb_sort ();
+       static void cb_close(Fl_Widget* w, void* p);
+       static void cb_add  (Fl_Widget* w, void* p);
+       static void cb_sort (Fl_Widget* w, void* p);
+       void cb_close();
+       void cb_add  ();
+       void cb_sort ();
 
 public:
 
-       gdPluginChooser(int x, int y, int w, int h, int stackType, Channel *ch=nullptr);
-  ~gdPluginChooser();
+       gdPluginChooser(int x, int y, int w, int h, int stackType, giada::m::Channel* ch=nullptr);
+       ~gdPluginChooser();
 };
 
 
index ab0f3fe49b0fa15400080fe8d20be057c2570965..b93e51d99d9249a940b5e478e2e565ed96fea02e 100644 (file)
@@ -54,7 +54,7 @@ using std::string;
 using namespace giada;
 
 
-gdPluginList::gdPluginList(int stackType, Channel* ch)
+gdPluginList::gdPluginList(int stackType, m::Channel* ch)
        : gdWindow(468, 204), ch(ch), stackType(stackType)
 {
        using namespace giada::m;
index d63ed05d49679532961f33abbe8272d35ccf5a56..c3513bc4816f2be9414f235480a153298b963998 100644 (file)
@@ -35,7 +35,6 @@
 
 
 class Fl_Scroll;
-class Channel;
 class geButton;
 
 
@@ -51,10 +50,10 @@ private:
 
 public:
 
-       Channel* ch;      // ch == nullptr ? masterOut
+       giada::m::Channel* ch;      // ch == nullptr ? masterOut
        int stackType;
 
-       gdPluginList(int stackType, Channel* ch=nullptr);
+       gdPluginList(int stackType, giada::m::Channel* ch=nullptr);
        ~gdPluginList();
 
        /* special callback, passed to browser. When closed (i.e. plugin
index 51b4c284e53d4da95792d950e0341e7bd76a125b..8dfca8b6d7b7245bdc359ae2159ff90b73e7de3d 100644 (file)
 #include "pluginWindow.h"
 
 
-gdPluginWindow::gdPluginWindow(Plugin* p)
+using namespace giada;
+
+
+gdPluginWindow::gdPluginWindow(m::Plugin* p)
  : gdWindow(450, 156), m_plugin(p)
 {
        set_non_modal();
index 49f753ede25374225bb99ead6b22f761741d6439..a34befec0cb5224cbff71407a161306d43a05079 100644 (file)
 #define GD_PLUGIN_WINDOW_H
 
 
+#include "../../core/plugin.h"
 #include "window.h"
 
 
-class Plugin;
 class geBox;
 class geSlider;
 class geLiquidScroll;
@@ -44,7 +44,7 @@ class gdPluginWindow : public gdWindow
 {
 private:
 
-       Plugin* m_plugin;
+       giada::m::Plugin* m_plugin;
 
        geLiquidScroll* m_list;
 
@@ -52,7 +52,7 @@ private:
 
 public:
 
-       gdPluginWindow(Plugin* p);
+       gdPluginWindow(giada::m::Plugin* p);
 
        void updateParameter(int index, bool changeSlider=false);
        void updateParameters(bool changeSlider=false);
index 004be476e61569641890dcc374e5416da9cf0794..8dd6779656652c9d1e6e0afdd3555728e63ea487 100644 (file)
 #endif
 
 
-class Plugin;
-
-
 class gdPluginWindowGUI : public gdWindow
 {
 private:
 
-       Plugin* m_plugin;
+       giada::m::Plugin* m_plugin;
 
        static void cb_close  (Fl_Widget* v, void* p);
        static void cb_refresh(void* data);
@@ -59,7 +56,7 @@ private:
 
 public:
 
-       gdPluginWindowGUI(Plugin* p);
+       gdPluginWindowGUI(giada::m::Plugin* p);
        ~gdPluginWindowGUI();
 };
 
index 4774df2ecbcc74cb6dc17644dd452bc35d32867d..b13ef70c5218f3d141528d025c325b601fb1db3c 100644 (file)
@@ -63,7 +63,7 @@ using std::string;
 using namespace giada;
 
 
-gdSampleEditor::gdSampleEditor(SampleChannel* ch)
+gdSampleEditor::gdSampleEditor(m::SampleChannel* ch)
   : gdWindow(640, 480),
     ch(ch)
 {
index 2d120541712b1a8632d686682c16115c7c20dbee..0ab76e6794922aed93838b0643ea39d105aef77e 100644 (file)
@@ -29,6 +29,7 @@
 #define GD_EDITOR_H
 
 
+#include "../../core/sampleChannel.h"
 #include "window.h"
 
 
@@ -78,7 +79,7 @@ private:
 
 public:
 
-       gdSampleEditor(SampleChannel* ch);
+       gdSampleEditor(giada::m::SampleChannel* ch);
        ~gdSampleEditor();
 
        void updateInfo();
@@ -106,7 +107,7 @@ public:
        geCheck* loop;
        geBox* info;
 
-       SampleChannel* ch;
+       giada::m::SampleChannel* ch;
 };
 
 
index ba0d5f4ebb0a5b942ca3e0004661b3befd434a23..1283c7a35feb1ac883aefc4418a37e7ce9518f45 100644 (file)
@@ -34,7 +34,7 @@ namespace giada {
 namespace v
 {
 geBaseAction::geBaseAction(Pixel X, Pixel Y, Pixel W, Pixel H, bool resizable,
-       giada::m::recorder::action a1, giada::m::recorder::action a2)
+       const m::Action* a1, const m::Action* a2)
 : Fl_Box     (X, Y, W, H),
   m_resizable(resizable),
   onRightEdge(false),
index d8bf4fd5c872be1683cc8f1df0ea6f6976687ffc..c3b4b1284db317df5ac3d0e615a04c59f2887784 100644 (file)
 
 
 namespace giada {
+namespace m 
+{
+class Action;
+}
 namespace v
 {
 class geBaseAction : public Fl_Box
 {
-private:
+protected:
        
        bool m_resizable;
 
@@ -49,7 +53,7 @@ public:
        static const Pixel HANDLE_WIDTH = 6;
 
        geBaseAction(Pixel x, Pixel y, Pixel w, Pixel h, bool resizable, 
-               m::recorder::action a1, m::recorder::action a2);
+               const m::Action* a1, const m::Action* a2);
 
        int handle(int e) override;
 
@@ -69,8 +73,8 @@ public:
        bool altered;
        Pixel pick;
 
-       m::recorder::action a1;
-       m::recorder::action a2;
+       const m::Action* a1;
+       const m::Action* a2;
 };
 }} // giada::v::
 
index c59b12d03e6a6eae0847817066de68663d21a2d6..75c6d2240b3b7f093986150e9404a2f8c863a87d 100644 (file)
 namespace giada {
 namespace v
 {
-geBaseActionEditor::geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, Channel* ch)
+geBaseActionEditor::geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, m::Channel* ch)
 :      Fl_Group(x, y, w, h),
-  m_ch    (ch),
-  m_base  (static_cast<gdBaseActionEditor*>(window())),
-  m_action(nullptr)
+       m_ch    (ch),
+       m_base  (static_cast<gdBaseActionEditor*>(window())),
+       m_action(nullptr)
 {
 }
 
index 0f3d2edf2717d22dac2de2a7bed982d9bdb1798b..bcd3cfb57d74ffdc041dda29cdfb28d51c9d4f55 100644 (file)
@@ -33,9 +33,6 @@
 #include <FL/Fl_Group.H>
 
 
-class Channel;
-
-
 namespace giada {
 namespace v
 {
@@ -57,7 +54,7 @@ private:
 
 protected:
 
-       Channel* m_ch;
+       m::Channel* m_ch;
 
        gdBaseActionEditor* m_base;
 
@@ -79,7 +76,7 @@ protected:
 
 public:
 
-       geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, Channel* ch);
+       geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, m::Channel* ch);
 
   /* updateActions
   Rebuild the actions widgets from scratch. */
index b1bba63cef8a6c8c16da8319dcdab565e673dcdb..ff27f5bffaa990f79f616074bb98dbb2b92fba85 100644 (file)
 #include "../../../utils/math.h"
 #include "../../../core/const.h"
 #include "../../../core/conf.h"
+#include "../../../core/action.h"
+#include "../../../core/recorder.h"
 #include "../../../core/sampleChannel.h"
-#include "../../../glue/recorder.h"
+#include "../../../glue/actionEditor.h"
 #include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "envelopePoint.h"
 #include "envelopeEditor.h"
@@ -44,13 +46,11 @@ using std::vector;
 namespace giada {
 namespace v
 {
-geEnvelopeEditor::geEnvelopeEditor(Pixel x, Pixel y, int actionType, const char* l, 
-       SampleChannel* ch)
-:      geBaseActionEditor(x, y, 200, m::conf::envelopeEditorH, ch),    
-  m_actionType      (actionType)
+geEnvelopeEditor::geEnvelopeEditor(Pixel x, Pixel y, const char* l, 
+       m::SampleChannel* ch)
+:      geBaseActionEditor(x, y, 200, m::conf::envelopeEditorH, ch)
 {
        copy_label(l);
-       rebuild();
 }
 
 
@@ -94,7 +94,7 @@ void geEnvelopeEditor::draw()
        for (int i=0; i<children(); i++) {
                geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
                if (m_action == nullptr)
-                       p->position(p->x(), valueToY(p->a1.fValue));
+                       p->position(p->x(), valueToY(p->a1->event.getVelocity()));
                if (i > 0) {
                        x2 = p->x() + side;
                        y2 = p->y() + side;
@@ -114,7 +114,7 @@ void geEnvelopeEditor::draw()
 void geEnvelopeEditor::rebuild()
 {
        namespace mr = m::recorder;
-       namespace cr = c::recorder;
+       namespace ca = c::actionEditor;
 
        /* Remove all existing actions and set a new width, according to the current
        zoom level. */
@@ -122,11 +122,10 @@ void geEnvelopeEditor::rebuild()
        clear();
        size(m_base->fullWidth, h());
 
-       vector<mr::action> actions = cr::getEnvelopeActions(m_ch, m_actionType);
-
-       for (mr::action a : actions) {
-               gu_log("[geEnvelopeEditor::rebuild] Action %d\n", a.frame);
-               add(new geEnvelopePoint(frameToX(a.frame), valueToY(a.fValue), a));             
+       for (const m::Action* a : m_base->getActions()) {
+               if (a->event.getStatus() != m::MidiEvent::ENVELOPE)
+                       continue;
+               add(new geEnvelopePoint(frameToX(a->frame), valueToY(a->event.getVelocity()), a));              
        }
 
        resizable(nullptr);
@@ -159,15 +158,15 @@ Pixel geEnvelopeEditor::frameToX(Frame frame) const
 }
 
 
-Pixel geEnvelopeEditor::valueToY(float value) const
+Pixel geEnvelopeEditor::valueToY(int value) const
 {
-       return u::math::map<float, Pixel>(value, 0.0, 1.0, y() + (h() - geEnvelopePoint::SIDE), y());
+       return u::math::map<int, Pixel>(value, 0, G_MAX_VELOCITY, y() + (h() - geEnvelopePoint::SIDE), y());
 }
 
 
-float geEnvelopeEditor::yToValue(Pixel pixel) const
+int geEnvelopeEditor::yToValue(Pixel pixel, Pixel offset) const
 {
-       return u::math::map<Pixel, float>(pixel, h() - geEnvelopePoint::SIDE, 0, 0.0, 1.0);     
+       return u::math::map<Pixel, int>(pixel, h() - offset, 0, 0, G_MAX_VELOCITY);     
 }
 
 
@@ -177,9 +176,11 @@ float geEnvelopeEditor::yToValue(Pixel pixel) const
 void geEnvelopeEditor::onAddAction()     
 {
        Frame f = m_base->pixelToFrame(Fl::event_x() - x());
-       float v = yToValue(Fl::event_y() - y());
-       c::recorder::recordEnvelopeAction(m_ch, m_actionType, f, v);
-       rebuild();
+       int   v = yToValue(Fl::event_y() - y());
+       
+       c::actionEditor::recordEnvelopeAction(m_ch, f, v);
+       
+       m_base->rebuild();
 }
 
 
@@ -188,8 +189,9 @@ void geEnvelopeEditor::onAddAction()
 
 void geEnvelopeEditor::onDeleteAction()  
 {
-       c::recorder::deleteEnvelopeAction(m_ch, m_action->a1, /*moved=*/false);
-       rebuild();
+       c::actionEditor::deleteEnvelopeAction(m_ch, m_action->a1);
+               
+       m_base->rebuild();
 }
 
 
@@ -225,9 +227,9 @@ void geEnvelopeEditor::onMoveAction()
 void geEnvelopeEditor::onRefreshAction() 
 {
        Frame f = m_base->pixelToFrame((m_action->x() - x()) + geEnvelopePoint::SIDE / 2);
-       float v = yToValue(m_action->y() - y());
-       c::recorder::deleteEnvelopeAction(m_ch, m_action->a1, /*moved=*/true);
-       c::recorder::recordEnvelopeAction(m_ch, m_actionType, f, v);
-       rebuild();
+       float v = yToValue(m_action->y() - y(), geEnvelopePoint::SIDE);
+       c::actionEditor::updateEnvelopeAction(m_ch, m_action->a1, f, v);
+
+       m_base->rebuild();
 }
 }} // giada::v::
\ No newline at end of file
index 0bdc8b574ec3c50c826d67e83daf287eb7dd1075..c8046df479cf206510442a1d80b1bbe7e7516c5d 100644 (file)
 #include "baseActionEditor.h"
 
 
-class SampleChannel;
 
 
 namespace giada {
+namespace m
+{
+class SampleChannel;
+}
 namespace v
 {
 class geEnvelopePoint;
@@ -45,11 +48,6 @@ class geEnvelopeEditor : public geBaseActionEditor
 {
 private:
 
-       /* m_actionType
-       What type of action this envelope editor is dealing with. */
-       
-       int m_actionType;
-
        void onAddAction()     override;
        void onDeleteAction()  override;
        void onMoveAction()    override;
@@ -57,15 +55,15 @@ private:
        void onRefreshAction() override;
 
        Pixel frameToX(Frame frame) const;
-       Pixel valueToY(float value) const;
-       float yToValue(Pixel pixel) const;
+       Pixel valueToY(int value) const;
+       int   yToValue(Pixel pixel, Pixel offset=0) const;
 
        bool isFirstPoint() const;
        bool isLastPoint()  const;
 
 public:
 
-       geEnvelopeEditor(Pixel x, Pixel y, int actionType, const char* l, SampleChannel* ch);
+       geEnvelopeEditor(Pixel x, Pixel y, const char* l, m::SampleChannel* ch);
        ~geEnvelopeEditor();
 
        void draw() override;
index a1f7e9e311479504b4b527a47bc5ed15205ab85f..a32965deaad2f989db5cf7fcf272a0f396e4f4c1 100644 (file)
@@ -33,8 +33,8 @@
 namespace giada {
 namespace v
 {
-geEnvelopePoint::geEnvelopePoint(Pixel X, Pixel Y, m::recorder::action a)
-       : geBaseAction(X, Y, SIDE, SIDE, /*resizable=*/false, a, {})
+geEnvelopePoint::geEnvelopePoint(Pixel X, Pixel Y, const m::Action* a)
+       : geBaseAction(X, Y, SIDE, SIDE, /*resizable=*/false, a, nullptr)
 {
 }
 
index 3e040ff4c99ccd9e5e1420e4085de31072b91b34..05f7bc3f27929cf549f4f276c1cd453324eb4ba0 100644 (file)
@@ -42,7 +42,7 @@ public:
 
        static const Pixel SIDE = 12;
 
-       geEnvelopePoint(Pixel x, Pixel y, m::recorder::action a);
+       geEnvelopePoint(Pixel x, Pixel y, const m::Action* a);
 
        void draw() override;
 };
index 0614b358ea9a4b90b967667b05af4674f28881e3..4992af7ef998b22c4fdeedd54372cb8784a6f512 100644 (file)
@@ -41,9 +41,7 @@ geNoteEditor::geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base)
 : geScroll(x, y, 200, 422),
        m_base  (base)
 {
-       pianoRoll = new gePianoRoll(x, y, m_base->fullWidth, static_cast<MidiChannel*>(m_base->ch));
-
-       rebuild();
+       pianoRoll = new gePianoRoll(x, y, m_base->fullWidth, static_cast<m::MidiChannel*>(m_base->ch));
        
        size(m_base->fullWidth, m::conf::pianoRollH);
        
index 5d0077a48df7d859e55adae93e2646bab03d943e..d6082769326eca99e72378a982133233ce0a30d0 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <FL/fl_draw.H>
 #include "../../../core/const.h"
+#include "../../../core/action.h"
 #include "../../../core/midiEvent.h"
 #include "../../../utils/math.h"
 #include "pianoItem.h"
 namespace giada {
 namespace v
 {
-gePianoItem::gePianoItem(Pixel X, Pixel Y, Pixel W, Pixel H, m::recorder::action a1,
-       m::recorder::action a2)
+gePianoItem::gePianoItem(Pixel X, Pixel Y, Pixel W, Pixel H, const m::Action* a1,
+       const m::Action* a2)
 : geBaseAction(X, Y, W, H, /*resizable=*/true, a1, a2),
-  orphaned    (a2.frame == -1)
+  m_ringLoop  (a2 != nullptr && a1->frame > a2->frame),
+  m_orphaned  (a2 == nullptr)
 {
+       m_resizable = isResizable();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool gePianoItem::isResizable() const
+{
+       return !(m_ringLoop || m_orphaned);
 }
 
 
@@ -53,14 +65,21 @@ void gePianoItem::draw()
        Pixel by = y() + 2;
        Pixel bh = h() - 3;
 
-       if (orphaned) {
-               fl_rect(x(), by, MIN_WIDTH, bh, color);
-               fl_line(x(), by, x() + MIN_WIDTH, by + bh);
+       if (m_orphaned) {
+               fl_rect(x(), by, w(), bh, color);
+               fl_line(x(), by, x() + w(), by + bh);
        }
        else {
                Pixel vh = calcVelocityH();
-               fl_rectf(x(), by + (bh - vh), w(), vh, color);
-               fl_rect(x(), by, w(), bh, color);
+               if (m_ringLoop) {
+                       fl_rect(x(), by, MIN_WIDTH, bh, color);
+                       fl_line(x() + MIN_WIDTH, by + bh/2, x() + w(), by + bh/2);
+                       fl_rectf(x(), by + (bh - vh), MIN_WIDTH, vh, color);
+               }
+               else {
+                       fl_rect(x(), by, w(), bh, color);
+                       fl_rectf(x(), by + (bh - vh), w(), vh, color);
+               }
        }
 }
 
@@ -70,7 +89,7 @@ void gePianoItem::draw()
 
 Pixel gePianoItem::calcVelocityH() const
 {
-       int v = m::MidiEvent(a1.iValue).getVelocity();
+       int v = a1->event.getVelocity();
        return u::math::map<int, Pixel>(v, 0, G_MAX_VELOCITY, 0, h() - 3);
 }
 }} // giada::v::
\ No newline at end of file
index da7c614b665dd2ac98c319e3c96a81efec5ba6ef..6f84cc980b45d6ffeb9512dc0437758f3717ca5c 100644 (file)
 #define GE_PIANO_ITEM_H
 
 
-#include "../../../core/recorder.h"
 #include "baseAction.h"
 
 
 namespace giada {
+namespace m 
+{
+class Action;
+}
 namespace v
 {
 class gdActionEditor;
@@ -43,16 +46,18 @@ class gePianoItem : public geBaseAction
 {
 private:
 
+       bool m_ringLoop;
+       bool m_orphaned;
+
        Pixel calcVelocityH() const;
 
 public:
 
-       gePianoItem(int x, int y, int w, int h, m::recorder::action a1, 
-               m::recorder::action a2);
+       gePianoItem(int x, int y, int w, int h, const m::Action* a1, const m::Action* a2);
  
        void draw() override;
 
-       bool orphaned;
+       bool isResizable() const;
 };
 }} // giada::v::
 
index c1b416bad5facdf81e62462c2d918358c51bbe46..f6291012d7ddd080ad2bb93cc6fae5f0f2f706c5 100644 (file)
 #include "../../../core/conf.h"
 #include "../../../core/const.h"
 #include "../../../core/clock.h"
+#include "../../../core/action.h"
+#include "../../../core/midiEvent.h"
 #include "../../../core/midiChannel.h"
 #include "../../../utils/log.h"
 #include "../../../utils/string.h"
 #include "../../../utils/math.h"
-#include "../../../glue/recorder.h"
+#include "../../../glue/actionEditor.h"
 #include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "pianoItem.h"
 #include "noteEditor.h"
@@ -48,12 +50,11 @@ using std::vector;
 namespace giada {
 namespace v
 {
-gePianoRoll::gePianoRoll(Pixel X, Pixel Y, Pixel W, MidiChannel* ch)
+gePianoRoll::gePianoRoll(Pixel X, Pixel Y, Pixel W, m::MidiChannel* ch)
        : geBaseActionEditor(X, Y, W, 40, ch),
          pick              (0)
 {
        position(x(), m::conf::pianoRollY == -1 ? y()-(h()/2) : m::conf::pianoRollY);
-       rebuild();
 }
 
 
@@ -219,7 +220,7 @@ void gePianoRoll::onAddAction()
 {
        Frame frame = m_base->pixelToFrame(Fl::event_x() - x());
        int   note  = yToNote(Fl::event_y() - y());
-       c::recorder::recordMidiAction(m_ch->index, note, G_MAX_VELOCITY, frame);
+       c::actionEditor::recordMidiAction(static_cast<m::MidiChannel*>(m_ch), note, G_MAX_VELOCITY, frame);
        
        m_base->rebuild();  // Rebuild velocityEditor as well
 }
@@ -230,7 +231,7 @@ void gePianoRoll::onAddAction()
 
 void gePianoRoll::onDeleteAction()
 {
-       c::recorder::deleteMidiAction(static_cast<MidiChannel*>(m_ch), m_action->a1, m_action->a2);     
+       c::actionEditor::deleteMidiAction(static_cast<m::MidiChannel*>(m_ch), m_action->a1);    
        
        m_base->rebuild();  // Rebuild velocityEditor as well
 }
@@ -264,7 +265,7 @@ void gePianoRoll::onMoveAction()
 
 void gePianoRoll::onResizeAction()
 {
-       if (static_cast<gePianoItem*>(m_action)->orphaned)
+       if (!static_cast<gePianoItem*>(m_action)->isResizable())
                return;
 
        Pixel ex = Fl::event_x();
@@ -286,10 +287,7 @@ void gePianoRoll::onResizeAction()
 
 void gePianoRoll::onRefreshAction()
 {
-       namespace cr = c::recorder;
-
-       if (static_cast<gePianoItem*>(m_action)->orphaned)
-               return;
+       namespace ca = c::actionEditor;
 
        Pixel p1 = m_action->x() - x();
        Pixel p2 = m_action->x() + m_action->w() - x();
@@ -303,26 +301,24 @@ void gePianoRoll::onRefreshAction()
        }       
        else if (m_action->onLeftEdge) {
                f1 = m_base->pixelToFrame(p1);
-               f2 = m_action->a2.frame;
+               f2 = m_action->a2->frame;
+               if (f1 == f2) // If snapping makes an action fall onto the other
+                       f1 -= G_DEFAULT_ACTION_SIZE;
        }
        else if (m_action->onRightEdge) {
-               f1 = m_action->a1.frame;
+               f1 = m_action->a1->frame;
                f2 = m_base->pixelToFrame(p2);
+               if (f1 == f2) // If snapping makes an action fall onto the other
+                       f2 += G_DEFAULT_ACTION_SIZE;
        }
 
-       assert(f1 != 0 && f2 != 0);
+       assert(f2 != 0);
 
        int note     = yToNote(m_action->y() - y());
-       int velocity = m::MidiEvent(m_action->a1.iValue).getVelocity();
+       int velocity = m_action->a1->event.getVelocity();
 
-       /* TODO - less then optimal. Let's wait for recorder refactoring... */
-       
-       int oldNote  = m::MidiEvent(m_action->a1.iValue).getNote();
-       cr::deleteMidiAction(static_cast<MidiChannel*>(m_ch), m_action->a1, m_action->a2);      
-       if (cr::midiActionCanFit(m_ch->index, note, f1, f2))
-               cr::recordMidiAction(m_ch->index, note, velocity, f1, f2);
-       else
-               cr::recordMidiAction(m_ch->index, oldNote, velocity, m_action->a1.frame, m_action->a2.frame);
+       ca::updateMidiAction(static_cast<m::MidiChannel*>(m_ch), m_action->a1, note, 
+               velocity, f1, f2);
 
        m_base->rebuild();  // Rebuild velocityEditor as well
 }
@@ -349,13 +345,23 @@ Pixel gePianoRoll::snapToY(Pixel p) const
 }
 
 
+Pixel gePianoRoll::getPianoItemW(Pixel px, const m::Action* a1, const m::Action* a2) const
+{
+       if (a2 != nullptr) {            // Regular
+               if (a1->frame > a2->frame)  // Ring-loop
+                       return m_base->loopWidth - (px - x());
+               return m_base->frameToPixel(a2->frame - a1->frame);
+       }
+       return geBaseAction::MIN_WIDTH; // Orphaned
+}
+
+
 /* -------------------------------------------------------------------------- */
 
 
 void gePianoRoll::rebuild()
 {
-       namespace mr = m::recorder;
-       namespace cr = c::recorder;
+       namespace ca = c::actionEditor;
 
        /* Remove all existing actions and set a new width, according to the current
        zoom level. */
@@ -363,23 +369,22 @@ void gePianoRoll::rebuild()
        clear();
        size(m_base->fullWidth, (MAX_KEYS + 1) * CELL_H);
 
-       vector<mr::Composite> actions = cr::getMidiActions(m_ch->index); 
-       for (mr::Composite comp : actions)
+       for (const m::Action* action : m_base->getActions())
        {
-               m::MidiEvent e1 = comp.a1.iValue;
-               m::MidiEvent e2 = comp.a2.iValue;
+               if (action->event.getStatus() == m::MidiEvent::NOTE_OFF)
+                       continue;
+
+               const m::Action* a1 = action;
+               const m::Action* a2 = action->next;
 
-               gu_log("[gePianoRoll::rebuild] ((0x%X, 0x%X, f=%d) - (0x%X, 0x%X, f=%d))\n", 
-                       e1.getStatus(), e1.getNote(), comp.a1.frame,
-                       e2.getStatus(), e2.getNote(), comp.a2.frame
-               );
+               assert(a1 != nullptr);  // a2 might be null if orphaned
 
-               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
-               Pixel py = y() + noteToY(e1.getNote());
-               Pixel pw = m_base->frameToPixel(comp.a2.frame - comp.a1.frame);
+               Pixel px = x() + m_base->frameToPixel(a1->frame);
+               Pixel py = y() + noteToY(a1->event.getNote());
                Pixel ph = CELL_H;
+               Pixel pw = getPianoItemW(px, a1, a2);
 
-               add(new gePianoItem(px, py, pw, ph, comp.a1, comp.a2));
+               add(new gePianoItem(px, py, pw, ph, a1, a2));
        }
 
        drawSurface1();
index 1fdfbbcd3d37fa918226a87b02edcdf04a85cc33..aedb641c8e630c38419c648450e5d529e96db5a0 100644 (file)
 #include "baseActionEditor.h"
 
 
-class MidiChannel;
 
 
 namespace giada {
+namespace m
+{
+class MidiChannel;
+}      
 namespace v
 {
 class gePianoRoll : public geBaseActionEditor
@@ -72,6 +75,7 @@ private:
        Pixel snapToY(Pixel p) const;
        int   yToNote(Pixel y) const;
        Pixel noteToY(int n) const;
+       Pixel getPianoItemW(Pixel x, const m::Action* a1, const m::Action* a2) const;
 
 public:
 
@@ -81,7 +85,7 @@ public:
        static const Pixel CELL_H    = 20;
        static const Pixel CELL_W    = 40;
 
-       gePianoRoll(Pixel x, Pixel y, Pixel w, MidiChannel* ch);
+       gePianoRoll(Pixel x, Pixel y, Pixel w, m::MidiChannel* ch);
 
        void draw() override;
        int  handle(int e) override;
index f4e7d9bc47cf058d19ae8d434a0320bd35bf0488..bd6975504a7f89ea18f16decfa5461f25b039020 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <FL/fl_draw.H>
 #include "../../../core/const.h"
+#include "../../../core/action.h"
 #include "../../../core/sampleChannel.h"
 #include "sampleAction.h"
 
@@ -35,7 +36,7 @@ namespace giada {
 namespace v
 {
 geSampleAction::geSampleAction(Pixel X, Pixel Y, Pixel W, Pixel H, 
-       const SampleChannel* ch, m::recorder::action a1, m::recorder::action a2)
+       const m::SampleChannel* ch, const m::Action* a1, const m::Action* a2)
 : geBaseAction(X, Y, W, H, ch->mode == ChannelMode::SINGLE_PRESS, a1, a2),
   m_ch        (ch)
 {
@@ -53,14 +54,14 @@ void geSampleAction::draw()
                fl_rectf(x(), y(), w(), h(), color);
        }
        else {
-               if (a1.type == G_ACTION_KILL)
+               if (a1->event.getStatus() == m::MidiEvent::NOTE_KILL)
                        fl_rect(x(), y(), MIN_WIDTH, h(), color);
                else {
                        fl_rectf(x(), y(), MIN_WIDTH, h(), color);
-                       if (a1.type == G_ACTION_KEYPRESS)
+                       if (a1->event.getStatus() == m::MidiEvent::NOTE_ON)
                                fl_rectf(x()+3, y()+h()-11, w()-6, 8, G_COLOR_GREY_4);
                        else
-                       if (a1.type == G_ACTION_KEYREL)
+                       if (a1->event.getStatus() == m::MidiEvent::NOTE_OFF)
                                fl_rectf(x()+3, y()+3, w()-6, 8, G_COLOR_GREY_4);
                }
        }
index 47a8116b8eeda48091a26fd918b6c17c2b137a11..e85ab13c42656fc932e15611fead5bc0056004d3 100644 (file)
 #include "baseAction.h"
 
 
-class SampleChannel;
 
 
 namespace giada {
+namespace m
+{
+class SampleChannel;
+class Action;
+}
 namespace v
 {
 class geSampleAction : public geBaseAction
 {
 private:
 
-       const SampleChannel* m_ch;
+       const m::SampleChannel* m_ch;
 
 public:
 
-       geSampleAction(Pixel x, Pixel y, Pixel w, Pixel h, const SampleChannel* ch,
-               m::recorder::action a1, m::recorder::action a2);
+       geSampleAction(Pixel x, Pixel y, Pixel w, Pixel h, const m::SampleChannel* ch,
+               const m::Action* a1, const m::Action* a2);
 
        void draw() override;
 };
index 25bdd91ac8f5f403783b126195ac481baa95744f..ae1cb9e86c31b98705ac6b71463fe2ba1bd61ed2 100644 (file)
 
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
+#include "../../../core/recorder.h"
 #include "../../../core/const.h"
 #include "../../../core/conf.h"
+#include "../../../core/action.h"
 #include "../../../core/sampleChannel.h"
 #include "../../../utils/log.h"
-#include "../../../glue/recorder.h"
+#include "../../../glue/actionEditor.h"
 #include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "sampleAction.h"
 #include "sampleActionEditor.h"
@@ -43,10 +45,9 @@ using std::vector;
 namespace giada {
 namespace v
 {
-geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, SampleChannel* ch)
+geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, m::SampleChannel* ch)
 : geBaseActionEditor(x, y, 200, m::conf::sampleActionEditorH, ch)
 {
-       rebuild();
 }
 
 
@@ -65,9 +66,9 @@ geSampleActionEditor::~geSampleActionEditor()
 void geSampleActionEditor::rebuild()
 {
        namespace mr = m::recorder;
-       namespace cr = c::recorder;
+       namespace ca = c::actionEditor;
 
-       const SampleChannel* ch = static_cast<const SampleChannel*>(m_ch);
+       const m::SampleChannel* ch = static_cast<const m::SampleChannel*>(m_ch);
 
        /* Remove all existing actions and set a new width, according to the current
        zoom level. */
@@ -75,21 +76,23 @@ void geSampleActionEditor::rebuild()
        clear();
        size(m_base->fullWidth, h());
 
-       vector<mr::Composite> comps = cr::getSampleActions(ch);
+       for (const m::Action* a1 : m_base->getActions()) {
 
-       for (mr::Composite comp : comps) {
-               gu_log("[geSampleActionEditor::rebuild] Action [%d, %d)\n", 
-                       comp.a1.frame, comp.a2.frame);
-               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
+               if (a1->event.getStatus() == m::MidiEvent::ENVELOPE || isNoteOffSinglePress(a1))
+                       continue;
+
+               const m::Action* a2 = a1->next;
+
+               Pixel px = x() + m_base->frameToPixel(a1->frame);
                Pixel py = y() + 4;
                Pixel pw = 0;
                Pixel ph = h() - 8;
-               if (comp.a2.frame != -1)
-                               pw = m_base->frameToPixel(comp.a2.frame - comp.a1.frame);
+               if (a2 != nullptr && ch->mode == ChannelMode::SINGLE_PRESS)
+                       pw = m_base->frameToPixel(a2->frame - a1->frame);
 
-               geSampleAction* a = new geSampleAction(px, py, pw, ph, ch, comp.a1, comp.a2);
-               add(a);
-               resizable(a);
+               geSampleAction* gsa = new geSampleAction(px, py, pw, ph, ch, a1, a2);
+               add(gsa);
+               resizable(gsa);
        }
 
        /* If channel is LOOP_ANY, deactivate it: a loop mode channel cannot hold 
@@ -130,9 +133,10 @@ void geSampleActionEditor::draw()
 void geSampleActionEditor::onAddAction()     
 {
        Frame f = m_base->pixelToFrame(Fl::event_x() - x());
-       c::recorder::recordSampleAction(static_cast<SampleChannel*>(m_ch), 
+       c::actionEditor::recordSampleAction(static_cast<m::SampleChannel*>(m_ch), 
                m_base->getActionType(), f);
-       rebuild();
+       
+       m_base->rebuild();
 }
 
 
@@ -141,8 +145,9 @@ void geSampleActionEditor::onAddAction()
 
 void geSampleActionEditor::onDeleteAction()  
 {
-       c::recorder::deleteSampleAction(static_cast<SampleChannel*>(m_ch), m_action->a1, m_action->a2);
-       rebuild();
+       c::actionEditor::deleteSampleAction(static_cast<m::SampleChannel*>(m_ch), m_action->a1);
+       
+       m_base->rebuild();
 }
 
 
@@ -186,15 +191,15 @@ void geSampleActionEditor::onResizeAction()
 
 void geSampleActionEditor::onRefreshAction() 
 {
-       namespace cr = c::recorder;
+       namespace ca = c::actionEditor;
 
-       SampleChannel* ch = static_cast<SampleChannel*>(m_ch);
+       m::SampleChannel* ch = static_cast<m::SampleChannel*>(m_ch);
 
        Pixel p1   = m_action->x() - x();
        Pixel p2   = m_action->x() + m_action->w() - x();
        Frame f1   = 0;
        Frame f2   = 0;
-       int   type = m_action->a1.type;
+       int   type = m_action->a1->event.getStatus();
 
        if (!m_action->isOnEdges()) {
                f1 = m_base->pixelToFrame(p1);
@@ -202,21 +207,26 @@ void geSampleActionEditor::onRefreshAction()
        }       
        else if (m_action->onLeftEdge) {
                f1 = m_base->pixelToFrame(p1);
-               f2 = m_action->a2.frame;
+               f2 = m_action->a2->frame;
        }
        else if (m_action->onRightEdge) {
-               f1 = m_action->a1.frame;
+               f1 = m_action->a1->frame;
                f2 = m_base->pixelToFrame(p2);
        }
 
-       /* TODO - less then optimal. Let's wait for recorder refactoring... */
+       ca::updateSampleAction(ch, m_action->a1, type, f1, f2);
+                       
+       m_base->rebuild();
+}
 
-       cr::deleteSampleAction(ch, m_action->a1, m_action->a2);
-       if (cr::sampleActionCanFit(ch, f1, f2))
-               cr::recordSampleAction(ch, type, f1, f2);
-       else
-               cr::recordSampleAction(ch, type, m_action->a1.frame, m_action->a2.frame);
-                               
-       rebuild();
+
+/* -------------------------------------------------------------------------- */
+
+
+bool geSampleActionEditor::isNoteOffSinglePress(const m::Action* a)
+{
+       const m::SampleChannel* ch = static_cast<const m::SampleChannel*>(m_ch);
+       return ch->mode == ChannelMode::SINGLE_PRESS && a->event.getStatus() == m::MidiEvent::NOTE_OFF;
 }
+
 }} // giada::v::
\ No newline at end of file
index 197973f0870a2cc3ddee48af75ca310ac2211788..c71d0ad3866dd961ee34837dccb5fd63ff892d99 100644 (file)
 #include "baseActionEditor.h"
 
 
-class SampleChannel;
-
-
 namespace giada {
+namespace m
+{
+class SampleChannel;
+class Action;
+}
 namespace v
 {
 class geSampleAction;
 
-
 class geSampleActionEditor : public geBaseActionEditor
 {
 private:
@@ -51,9 +52,11 @@ private:
        void onResizeAction()  override;
        void onRefreshAction() override;
 
+    bool isNoteOffSinglePress(const m::Action* a);
+
 public:
 
-       geSampleActionEditor(Pixel x, Pixel y, SampleChannel* ch);
+       geSampleActionEditor(Pixel x, Pixel y, m::SampleChannel* ch);
        ~geSampleActionEditor();
 
        void draw() override;
index faaefebb90d456f8a3f60e97dcc46f921af2d6e8..58bcc6e39f815835e0025a155fa4d7b318bf68a8 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
+#include <cassert>
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
 #include "../../../utils/log.h"
 #include "../../../utils/math.h"
 #include "../../../core/const.h"
 #include "../../../core/conf.h"
+#include "../../../core/action.h"
 #include "../../../core/clock.h"
 #include "../../../core/midiChannel.h"
-#include "../../../glue/recorder.h"
+#include "../../../glue/actionEditor.h"
 #include "../../dialogs/actionEditor/baseActionEditor.h"
 #include "envelopePoint.h"
 #include "velocityEditor.h"
@@ -45,10 +47,9 @@ using std::vector;
 namespace giada {
 namespace v
 {
-geVelocityEditor::geVelocityEditor(Pixel x, Pixel y, MidiChannel* ch)
+geVelocityEditor::geVelocityEditor(Pixel x, Pixel y, m::MidiChannel* ch)
 :      geBaseActionEditor(x, y, 200, m::conf::velocityEditorH, ch)
 {
-       rebuild();
 }
 
 
@@ -82,7 +83,7 @@ void geVelocityEditor::draw()
        for (int i=0; i<children(); i++) {
                geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
                if (m_action == nullptr)
-                       p->position(p->x(), valueToY(m::MidiEvent(p->a1.iValue).getVelocity()));
+                       p->position(p->x(), valueToY(p->a1->event.getVelocity()));
                Pixel x1 = p->x() + side;
                Pixel y1 = p->y();
                Pixel y2 = y() + h();
@@ -105,7 +106,7 @@ Pixel geVelocityEditor::valueToY(int v) const
 
 int geVelocityEditor::yToValue(Pixel px) const
 {
-       return u::math::map<Pixel, int>(px, h() - geEnvelopePoint::SIDE, 1, 0, G_MAX_VELOCITY); 
+       return u::math::map<Pixel, int>(px, h() - geEnvelopePoint::SIDE, 0, 0, G_MAX_VELOCITY); 
 }
 
 
@@ -114,8 +115,7 @@ int geVelocityEditor::yToValue(Pixel px) const
 
 void geVelocityEditor::rebuild()
 {
-       namespace mr = m::recorder;
-       namespace cr = c::recorder;
+       namespace ca = c::actionEditor;
 
        /* Remove all existing actions and set a new width, according to the current
        zoom level. */
@@ -123,15 +123,17 @@ void geVelocityEditor::rebuild()
        clear();
        size(m_base->fullWidth, h());
 
-       vector<mr::Composite> actions = cr::getMidiActions(m_ch->index); 
-       for (mr::Composite comp : actions)
+       for (const m::Action* action : m_base->getActions())
        {
-               gu_log("[geVelocityEditor::rebuild] f=%d\n", comp.a1.frame);
+               if (action->event.getStatus() == m::MidiEvent::NOTE_OFF)
+                       continue;
+               
+               //gu_log("[geVelocityEditor::rebuild] f=%d\n", action->frame);
 
-               Pixel px = x() + m_base->frameToPixel(comp.a1.frame);
-               Pixel py = y() + valueToY(m::MidiEvent(comp.a1.iValue).getVelocity());
+               Pixel px = x() + m_base->frameToPixel(action->frame);
+               Pixel py = y() + valueToY(action->event.getVelocity());
 
-               add(new geEnvelopePoint(px, py, comp.a1));
+               add(new geEnvelopePoint(px, py, action));
        }
        
        resizable(nullptr);
@@ -161,7 +163,8 @@ void geVelocityEditor::onMoveAction()
 
 void geVelocityEditor::onRefreshAction() 
 {
-       c::recorder::setVelocity(m_ch, m_action->a1, yToValue(m_action->y() - y()));
+       c::actionEditor::updateVelocity(static_cast<m::MidiChannel*>(m_ch), m_action->a1, 
+               yToValue(m_action->y() - y()));
 
        m_base->rebuild();  // Rebuild pianoRoll as well
 }
index 40120c2bfaa5646adbe66c4b23f0b055ea3e715a..f3415ddbad8d62e692ddd185de4ac3b386da93d5 100644 (file)
 #include "baseActionEditor.h"
 
 
-class MidiChannel;
 
 
 namespace giada {
+namespace m
+{
+class MidiChannel;
+}
 namespace v
 {
 class geEnvelopePoint;
@@ -56,7 +59,7 @@ private:
 
 public:
 
-       geVelocityEditor(Pixel x, Pixel y, MidiChannel* ch);
+       geVelocityEditor(Pixel x, Pixel y, m::MidiChannel* ch);
        ~geVelocityEditor();
 
        void draw() override;
index 6717d332a656692e8f732a805997be0f201124db..6831a09589af37c5e8936a42a0c4d15678b25a5f 100644 (file)
 
 
 geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type)
-  : Fl_Box   (X, Y, W, H), 
-    m_type   (type),
-    m_minSize(minSize),
-    m_lastPos(0),
-    m_hover  (false)
+       : Fl_Box   (X, Y, W, H), 
+         m_type   (type),
+         m_minSize(minSize),
+         m_lastPos(0),
+         m_hover  (false)
 {
-  if (m_type == VERTICAL) {
-    m_origSize = H;
-    labelsize(H);
-  }
-  else {
-    m_origSize = W;
-    labelsize(W);
-  }
-  align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
-  labelfont(FL_COURIER);
-  visible_focus(0);
+       if (m_type == VERTICAL) {
+               m_origSize = H;
+               labelsize(H);
+       }
+       else {
+               m_origSize = W;
+               labelsize(W);
+       }
+       align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
+       labelfont(FL_COURIER);
+       visible_focus(0);
 }
 
 
@@ -74,64 +74,64 @@ geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type)
 
 void geResizerBar::handleDrag(int diff)
 {
-  Fl_Scroll* grp = static_cast<Fl_Scroll*>(parent());
-  int top;
-  int bot;
-  if (m_type == VERTICAL) {
-    top = y();
-    bot = y()+h();
-  }
-  else {
-    top = x();
-    bot = x()+w();
-  }
-
-  // First pass: find widget directly above us with common edge
-  //    Possibly clamp 'diff' if widget would get too small..
-
-  for (int t=0; t<grp->children(); t++) {
-    Fl_Widget* wd = grp->child(t);
-    if (m_type == VERTICAL) {
-      if ((wd->y()+wd->h()) == top) {                          // found widget directly above?
-        if ((wd->h()+diff) < m_minSize)
-          diff = wd->h() - m_minSize;                          // clamp
-        wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);   // change height
-        break;                                                 // done with first pass
-      }
-    }
-    else {
-      if ((wd->x()+wd->w()) == top) {                          // found widget directly above?
-        if ((wd->w()+diff) < m_minSize)
-          diff = wd->w() - m_minSize;                          // clamp
-        wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());   // change height
-        break;                                                 // done with first pass
-      }
-    }
-  }
-
-  // Second pass: find widgets below us, move based on clamped diff
-
-  for (int t=0; t<grp->children(); t++) {
-    Fl_Widget* wd = grp->child(t);
-    if (m_type == VERTICAL) {
-      if (wd->y() >= bot)                                     // found widget below us?
-        wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());  // change position
-    }
-    else {
-      if (wd->x() >= bot)
-        wd->resize(wd->x()+diff, wd->y(), wd->w(), wd->h());
-    }
-  }
-
-  // Change our position last
-
-  if (m_type == VERTICAL)
-    resize(x(), y()+diff, w(), h());
-  else
-    resize(x()+diff, y(), w(), h());
-
-  grp->init_sizes();
-  grp->redraw();
+       Fl_Scroll* grp = static_cast<Fl_Scroll*>(parent());
+       int top;
+       int bot;
+       if (m_type == VERTICAL) {
+               top = y();
+               bot = y()+h();
+       }
+       else {
+               top = x();
+               bot = x()+w();
+       }
+
+       // First pass: find widget directly above us with common edge
+       //    Possibly clamp 'diff' if widget would get too small..
+
+       for (int t=0; t<grp->children(); t++) {
+               Fl_Widget* wd = grp->child(t);
+               if (m_type == VERTICAL) {
+                       if ((wd->y()+wd->h()) == top) {                          // found widget directly above?
+                               if ((wd->h()+diff) < m_minSize)
+                                       diff = wd->h() - m_minSize;                          // clamp
+                               wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff);   // change height
+                               break;                                                 // done with first pass
+                       }
+               }
+               else {
+                       if ((wd->x()+wd->w()) == top) {                          // found widget directly above?
+                               if ((wd->w()+diff) < m_minSize)
+                                       diff = wd->w() - m_minSize;                          // clamp
+                               wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h());   // change height
+                               break;                                                 // done with first pass
+                       }
+               }
+       }
+
+       // Second pass: find widgets below us, move based on clamped diff
+
+       for (int t=0; t<grp->children(); t++) {
+               Fl_Widget* wd = grp->child(t);
+               if (m_type == VERTICAL) {
+                       if (wd->y() >= bot)                                     // found widget below us?
+                               wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h());  // change position
+               }
+               else {
+                       if (wd->x() >= bot)
+                               wd->resize(wd->x()+diff, wd->y(), wd->w(), wd->h());
+               }
+       }
+
+       // Change our position last
+
+       if (m_type == VERTICAL)
+               resize(x(), y()+diff, w(), h());
+       else
+               resize(x()+diff, y(), w(), h());
+
+       grp->init_sizes();
+       grp->redraw();
 }
 
 
@@ -150,40 +150,40 @@ void geResizerBar::draw()
 
 int geResizerBar::handle(int e)
 {
-  int ret = 0;
-  int this_y;
-  if (m_type == VERTICAL)
-    this_y = Fl::event_y_root();
-  else
-    this_y = Fl::event_x_root();
-  switch (e) {
-    case FL_FOCUS:
-      ret = 1;
-      break;
-    case FL_ENTER:
-      ret = 1;
-      fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
-      m_hover = true;
-      redraw();
-      break;
-    case FL_LEAVE:
-      ret = 1;
-      fl_cursor(FL_CURSOR_DEFAULT);
-      m_hover = false;
-      redraw();
-      break;
-    case FL_PUSH:
-      ret = 1;
-      m_lastPos = this_y;
-      break;
-    case FL_DRAG:
-      handleDrag(this_y-m_lastPos);
-      m_lastPos = this_y;
-      ret = 1;
-      break;
-    default: break;
-  }
-  return(Fl_Box::handle(e) | ret);
+       int ret = 0;
+       int this_y;
+       if (m_type == VERTICAL)
+               this_y = Fl::event_y_root();
+       else
+               this_y = Fl::event_x_root();
+       switch (e) {
+               case FL_FOCUS:
+                       ret = 1;
+                       break;
+               case FL_ENTER:
+                       ret = 1;
+                       fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
+                       m_hover = true;
+                       redraw();
+                       break;
+               case FL_LEAVE:
+                       ret = 1;
+                       fl_cursor(FL_CURSOR_DEFAULT);
+                       m_hover = false;
+                       redraw();
+                       break;
+               case FL_PUSH:
+                       ret = 1;
+                       m_lastPos = this_y;
+                       break;
+               case FL_DRAG:
+                       handleDrag(this_y-m_lastPos);
+                       m_lastPos = this_y;
+                       ret = 1;
+                       break;
+               default: break;
+       }
+       return(Fl_Box::handle(e) | ret);
 }
 
 
index 25db7e83c4dac811446a7c926842f1fc621c004a..12dc3832d9e02ced1baf31a395c75d3de5aa8642 100644 (file)
@@ -40,12 +40,12 @@ class geBrowser : public Fl_File_Browser
 private:
 
        std::string m_currentDir;
-  bool m_showHiddenFiles;
+       bool m_showHiddenFiles;
 
        /* normalize
        Makes sure the std::string never ends with a trailing slash. */
 
-       std::string normalize(const std::string &s);
+       std::string normalize(const std::strings);
 
 public:
 
@@ -56,7 +56,7 @@ public:
        /* init
        Initializes browser and show 'dir' as initial directory. */
 
-       void loadDir(const std::string &dir);
+       void loadDir(const std::stringdir);
 
        /* getSelectedItem
        Returns the full path or just the displayed name of the i-th selected item.
index 83b37e2f9baa1e053d41543013f4bba62f3bf9a3..2d563ce2ac44e820a5bf1493b8c03ccd2ca21c30 100644 (file)
@@ -49,7 +49,7 @@ extern gdMainWindow* G_MainWin;
 using namespace giada;
 
 
-geChannel::geChannel(int X, int Y, int W, int H, Channel* ch)
+geChannel::geChannel(int X, int Y, int W, int H, giada::m::Channel* ch)
  : Fl_Group(X, Y, W, H, nullptr),
         ch      (ch)
 {
index 7bff681db78839b7bb908889143e130572f20032..785b94dd7fa784ea4b06c42a9a4ef2dd097d2649 100644 (file)
@@ -31,9 +31,9 @@
 
 #include <FL/Fl_Group.H>
 #include "../../../../core/types.h"
+#include "../../../../core/channel.h"
 
 
-class Channel;
 class geIdButton;
 class geChannelStatus;
 class geButton;
@@ -101,7 +101,7 @@ protected:
 
 public:
 
-       geChannel(int x, int y, int w, int h, Channel* ch);
+       geChannel(int x, int y, int w, int h, giada::m::Channel* ch);
 
        /* reset
         * reset channel to initial status. */
@@ -137,7 +137,7 @@ public:
 
        int getSize();
 
-       Channel* ch;
+       giada::m::Channel* ch;
  
        geIdButton*      button;
        geChannelStatus* status;
index e47efb02d7f50a368260edea3c61514e20732563..d67abae7e72fcaa2705714c66d27df845532a2c1 100644 (file)
@@ -39,7 +39,7 @@
 using namespace giada;
 
 
-geChannelMode::geChannelMode(int x, int y, int w, int h, SampleChannel *ch,
+geChannelMode::geChannelMode(int x, int y, int w, int h, m::SampleChannel *ch,
   const char *L)
   : Fl_Menu_Button(x, y, w, h, L), ch(ch)
 {
index 349474ff492487d04ac4343721285707acef04d5..248c2f57684e4817cf2d5aceeb187ea39bf4674d 100644 (file)
@@ -41,11 +41,11 @@ private:
        static void cb_changeMode  (Fl_Widget *v, void *p);
        inline void __cb_changeMode(int mode);
 
-       class SampleChannel *ch;
+       giada::m::SampleChannel *ch;
 
 public:
 
-  geChannelMode(int x, int y, int w, int h, class SampleChannel *ch,
+  geChannelMode(int x, int y, int w, int h, giada::m::SampleChannel *ch,
     const char *l=0);
        void draw();
 };
index cc9f2d89c190ee6e2fd09347746348204436f8e1..e5171e3e8b6e938ea06a2ea3b52d3b5cfa13500a 100644 (file)
@@ -65,17 +65,17 @@ void geChannelStatus::draw()
   if (ch->status == ChannelStatus::PLAY)
     fl_rect(x(), y(), w(), h(), G_COLOR_LIGHT_1);
   else
-    fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);     // status empty
+    fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);  // status empty
 
 
   if (mixer::recording && ch->armed)
     fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_RED);     // take in progress
   else
-  if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording))
-    fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_BLUE);     // action record
+  if (recorder::isActive())
+    fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_BLUE);    // action recording
 
-  /* equation for the progress bar:
-   * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */
+  /* Equation for the progress bar: 
+  ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */
 
   int pos = ch->getPosition();
   if (pos == -1)
index ec12d2935a11af02a61a3cf98b4ae9b13b5f5dec..8e8bd5e89151bcc226ab076379dd42a1c5a5846b 100644 (file)
 class geChannelStatus : public Fl_Box
 {
 public:
-       geChannelStatus(int X, int Y, int W, int H, class SampleChannel *ch,
+       geChannelStatus(int X, int Y, int W, int H, giada::m::SampleChannel *ch,
     const char *L=0);
        void draw();
-       class SampleChannel *ch;
+       giada::m::SampleChannel *ch;
 };
 
 
index 7bfdf49f3f06d9ec5fec168e572c333c29242eb7..b63f2f214b2939483551c2102a60ab5a6f2b4729 100644 (file)
@@ -111,7 +111,7 @@ int geColumn::handle(int e)
                        int result = 0;
                        for (string& path : paths) {
                                gu_log("[geColumn::handle] loading %s...\n", path.c_str());
-                               SampleChannel* c = static_cast<SampleChannel*>(c::channel::addChannel(
+                               m::SampleChannel* c = static_cast<m::SampleChannel*>(c::channel::addChannel(
                                        m_index, ChannelType::SAMPLE, G_GUI_CHANNEL_H_1));
                                result = c::channel::loadChannel(c, gu_stripFileUrl(path));
                                if (result != G_RES_OK) {
@@ -210,7 +210,7 @@ void geColumn::repositionChannels()
 /* -------------------------------------------------------------------------- */
 
 
-geChannel* geColumn::addChannel(Channel* ch, int size)
+geChannel* geColumn::addChannel(m::Channel* ch, int size)
 {
        geChannel* gch = nullptr;
 
@@ -218,9 +218,9 @@ geChannel* geColumn::addChannel(Channel* ch, int size)
        repositioned later on during geColumn::resize(). */
 
        if (ch->type == ChannelType::SAMPLE)
-               gch = new geSampleChannel(x(), 0, w(), size, static_cast<SampleChannel*>(ch));
+               gch = new geSampleChannel(x(), 0, w(), size, static_cast<m::SampleChannel*>(ch));
        else
-               gch = new geMidiChannel(x(), 0, w(), size, static_cast<MidiChannel*>(ch));
+               gch = new geMidiChannel(x(), 0, w(), size, static_cast<m::MidiChannel*>(ch));
 
        add(gch);
 
@@ -297,7 +297,7 @@ void geColumn::clear(bool full)
 /* -------------------------------------------------------------------------- */
 
 
-Channel* geColumn::getChannel(int i)
+m::Channel* geColumn::getChannel(int i)
 {
        return static_cast<geChannel*>(child(i + 1))->ch;  // Skip "add channel"
 }
index 582b052c77645d598adfaa3c16c789ce76d11cb0..b980100081c3b70dfdc30ed2e13f4fd2dc85db8e 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class Channel;
 class geButton;
 class geChannel;
 class geResizerBar;
@@ -61,11 +60,11 @@ public:
        Adds a new channel in this column and set the internal pointer to channel 
        to 'ch'. */
 
-       geChannel* addChannel(Channel* ch, int size);
+       geChannel* addChannel(giada::m::Channel* ch, int size);
 
        int handle(int e) override;
        void draw() override;
-  void resize(int x, int y, int w, int h) override;
+       void resize(int x, int y, int w, int h) override;
 
        /* clear
        Removes all channels from the column. If full==true, delete also the "add new 
@@ -85,7 +84,7 @@ public:
 
        void refreshChannels();
 
-       Channel* getChannel(int i);
+       giada::m::Channel* getChannel(int i);
        int getIndex();
        void setIndex(int i);
        bool isEmpty();   
index 5deaea930715d2223864d6cea86a1946829c884e..10bfbb95bd7182c9c73a2df4349ee0c43cd935e7 100644 (file)
@@ -37,6 +37,9 @@
 #include "keyboard.h"
 
 
+using namespace giada;
+
+
 int geKeyboard::indexColumn = 0;
 
 
@@ -165,7 +168,7 @@ void geKeyboard::cb_addColumn(Fl_Widget* v, void* p)
 /* -------------------------------------------------------------------------- */
 
 
-geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, int size, bool build)
+geChannel* geKeyboard::addChannel(int colIndex, m::Channel* ch, int size, bool build)
 {
        geColumn* col = getColumnByIndex(colIndex);
 
@@ -232,7 +235,7 @@ int geKeyboard::handle(int e)
                        if (e == FL_KEYDOWN) {
                                if (Fl::event_key() == FL_BackSpace && !bckspcPressed) {
                                        bckspcPressed = true;
-                                       glue_rewindSeq(false);          // not from GUI
+                                       transport::rewindSeq(false);          // not from GUI
                                        ret = 1;
                                        break;
                                }
@@ -250,7 +253,7 @@ int geKeyboard::handle(int e)
                                }
                                else if (Fl::event_key() == ' ' && !spacePressed) {
                                        spacePressed = true;
-          glue_startStopSeq(false);      // unot from GUI
+                                       transport::startStopSeq(false);      // unot from GUI
                                        ret = 1;
                                        break;
                                }
index 84468772d8b7965c735e250d9dc31917b090aa74..339394e5ebc7e9240e7b1084e5542993e11b545a 100644 (file)
@@ -32,9 +32,9 @@
 #include <vector>
 #include <FL/Fl_Scroll.H>
 #include "../../../../core/const.h"
+#include "../../../../core/channel.h"
 
 
-class Channel;
 class geButton;
 class geColumn;
 class geChannel;
@@ -89,7 +89,7 @@ public:
        Requires Channel (and not geChannel). If build is set to true, also generate 
        the corresponding column if column (index) does not exist yet. */
 
-       geChannel* addChannel(int column, Channel* ch, int size, bool build=false);
+       geChannel* addChannel(int column, giada::m::Channel* ch, int size, bool build=false);
 
        /* addColumn
         * add a new column to the top of the stack. */
index 9c42a8ce3bed1596c286457a65f2ce6dfcfa9877..ab2c670ff3bab8eff6ef5a19faff672b031a1990 100644 (file)
@@ -29,6 +29,7 @@
 #include "../../../../core/const.h"
 #include "../../../../core/graphics.h"
 #include "../../../../core/midiChannel.h"
+#include "../../../../core/recorder.h"
 #include "../../../../utils/gui.h"
 #include "../../../../utils/string.h"
 #include "../../../../glue/channel.h"
@@ -54,6 +55,7 @@
 extern gdMainWindow* G_MainWin;
 
 
+using namespace giada;
 using std::string;
 
 
@@ -87,8 +89,8 @@ void menuCallback(Fl_Widget* w, void* v)
 {
        using namespace giada;
 
-       geMidiChannel* gch = static_cast<geMidiChannel*>(w);
-       MidiChannel*   ch  = static_cast<MidiChannel*>(gch->ch);
+       geMidiChannel*  gch = static_cast<geMidiChannel*>(w);
+       m::MidiChannel* ch  = static_cast<m::MidiChannel*>(gch->ch);
 
        Menu selectedItem = (Menu) (intptr_t) v;
 
@@ -148,7 +150,7 @@ void menuCallback(Fl_Widget* w, void* v)
 /* -------------------------------------------------------------------------- */
 
 
-geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel* ch)
+geMidiChannel::geMidiChannel(int X, int Y, int W, int H, m::MidiChannel* ch)
        : geChannel(X, Y, W, H, ch)
 {
        begin();
@@ -218,7 +220,7 @@ void geMidiChannel::cb_button()
        using namespace giada;
        
        if (button->value())
-               c::io::keyPress(static_cast<MidiChannel*>(ch), Fl::event_ctrl(), Fl::event_shift(), 0);
+               c::io::keyPress(static_cast<m::MidiChannel*>(ch), Fl::event_ctrl(), Fl::event_shift(), 0);
 }
 
 
@@ -241,9 +243,9 @@ void geMidiChannel::cb_openMenu()
                        {"Large",   0, menuCallback, (void*) Menu::RESIZE_H3},
                        {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
                        {0},
-               {"Rename channel",  0, menuCallback, (void*) Menu::RENAME_CHANNEL},
-               {"Clone channel",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
-               {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
+               {"Rename", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
+               {"Clone",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
+               {"Delete", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
                {0}
        };
 
@@ -271,6 +273,8 @@ void geMidiChannel::cb_openMenu()
 void geMidiChannel::refresh()
 {
        setColorsByStatus(ch->status, ch->recStatus);
+       if (m::recorder::isActive() && ch->armed)
+               mainButton->setActionRecordMode();
        mainButton->redraw();
 }
 
@@ -290,7 +294,7 @@ void geMidiChannel::reset()
 
 void geMidiChannel::update()
 {
-       const MidiChannel* mch = static_cast<const MidiChannel*>(ch);
+       const m::MidiChannel* mch = static_cast<const m::MidiChannel*>(ch);
 
        string label; 
        if (mch->name.empty())
index b3bfcd4e710e86f325ca70b7b78debf83c8fbaad..43b9ce8addb77e7254793f7d2546278de1677136 100644 (file)
 #define GE_MIDI_CHANNEL_H
 
 
+#include "../../../../core/midiChannel.h"
 #include "channel.h"
 #include "channelButton.h"
 
 
-class MidiChannel;
-
-
 class geMidiChannel : public geChannel
 {
 private:
@@ -47,7 +45,7 @@ private:
 
 public:
 
-       geMidiChannel(int x, int y, int w, int h, MidiChannel* ch);
+       geMidiChannel(int x, int y, int w, int h, giada::m::MidiChannel* ch);
 
        void resize(int x, int y, int w, int h) override;
 
index e82446fd10215a09275790aa85d26b3c6de1f9ea..785f0f927f3b7f8f76588f25336b73da3eb74864 100644 (file)
@@ -30,6 +30,7 @@
 #include "../../../../core/clock.h"
 #include "../../../../core/graphics.h"
 #include "../../../../core/wave.h"
+#include "../../../../core/recorder.h"
 #include "../../../../core/sampleChannel.h"
 #include "../../../../glue/io.h"
 #include "../../../../glue/channel.h"
@@ -101,8 +102,8 @@ void menuCallback(Fl_Widget* w, void* v)
 {
        using namespace giada;
 
-       geSampleChannel* gch = static_cast<geSampleChannel*>(w);
-       SampleChannel*   ch  = static_cast<SampleChannel*>(gch->ch);
+       geSampleChannel*  gch = static_cast<geSampleChannel*>(w);
+       m::SampleChannel* ch  = static_cast<m::SampleChannel*>(gch->ch);
 
        Menu selectedItem = (Menu) (intptr_t) v;
 
@@ -209,7 +210,7 @@ void menuCallback(Fl_Widget* w, void* v)
 /* -------------------------------------------------------------------------- */
 
 
-geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel* ch)
+geSampleChannel::geSampleChannel(int X, int Y, int W, int H, m::SampleChannel* ch)
        : geChannel(X, Y, W, H, ch)
 {
        begin();
@@ -297,12 +298,12 @@ void geSampleChannel::cb_openMenu()
        /* If you're recording (input or actions) no menu is allowed; you can't do
        anything, especially deallocate the channel */
 
-       if (m::mixer::recording || m::recorder::active)
+       if (m::mixer::recording || m::recorder::isActive())
                return;
 
        Fl_Menu_Item rclick_menu[] = {
                {"Input monitor",            0, menuCallback, (void*) Menu::INPUT_MONITOR,
-                       FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
+                       FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<m::SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
                {"Load new sample...",       0, menuCallback, (void*) Menu::LOAD_SAMPLE},
                {"Export sample to file...", 0, menuCallback, (void*) Menu::EXPORT_SAMPLE},
                {"Setup keyboard input...",  0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
@@ -321,10 +322,10 @@ void geSampleChannel::cb_openMenu()
                        {"Large",   0, menuCallback, (void*) Menu::RESIZE_H3},
                        {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
                        {0},
-               {"Rename channel", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
-               {"Clone channel",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
-               {"Free channel",   0, menuCallback, (void*) Menu::FREE_CHANNEL},
-               {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
+               {"Rename", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
+               {"Clone",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
+               {"Free",   0, menuCallback, (void*) Menu::FREE_CHANNEL},
+               {"Delete", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
                {0}
        };
 
@@ -344,7 +345,7 @@ void geSampleChannel::cb_openMenu()
        /* No 'clear start/stop actions' for those channels in loop mode: they cannot
        have start/stop actions. */
 
-       if (static_cast<SampleChannel*>(ch)->isAnyLoopMode())
+       if (static_cast<m::SampleChannel*>(ch)->isAnyLoopMode())
                rclick_menu[(int) Menu::CLEAR_ACTIONS_START_STOP].deactivate();
 
        Fl_Menu_Button* b = new Fl_Menu_Button(0, 0, 100, 50);
@@ -366,7 +367,7 @@ void geSampleChannel::cb_openMenu()
 void geSampleChannel::cb_readActions()
 {
        using namespace giada::c::channel;
-       toggleReadingActions(static_cast<SampleChannel*>(ch));
+       toggleReadingActions(static_cast<m::SampleChannel*>(ch));
 }
 
 
@@ -382,13 +383,11 @@ void geSampleChannel::refresh()
 
        setColorsByStatus(ch->status, ch->recStatus);
 
-       if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
+       if (static_cast<m::SampleChannel*>(ch)->wave != nullptr) {
                if (m::mixer::recording && ch->armed)
                        mainButton->setInputRecordMode();
-               if (m::recorder::active) {
-                       if (m::recorder::canRec(ch, m::clock::isRunning(), m::mixer::recording))
-                               mainButton->setActionRecordMode();
-               }
+               if (m::recorder::isActive())
+                       mainButton->setActionRecordMode();
                status->redraw(); // status invisible? sampleButton too (see below)
        }
        mainButton->redraw();
@@ -412,7 +411,7 @@ void geSampleChannel::reset()
 
 void geSampleChannel::update()
 {
-       const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
+       const m::SampleChannel* sch = static_cast<const m::SampleChannel*>(ch);
 
        switch (sch->status) {
                case ChannelStatus::EMPTY:
@@ -462,7 +461,7 @@ void geSampleChannel::update()
 
 void geSampleChannel::showActionButton()
 {
-       readActions->value(static_cast<SampleChannel*>(ch)->readActions);
+       readActions->value(static_cast<m::SampleChannel*>(ch)->readActions);
        readActions->show();
        packWidgets();
        redraw();
index 0d544c0f05348d41de217d5f151eedadffb517fd..0d43db954a75b0bdcfb71fd68592d1b91c50b618 100644 (file)
 #define GE_SAMPLE_CHANNEL_H
 
 
+#include "../../../../core/sampleChannel.h"
 #include "channel.h"
 
 
-class SampleChannel;
 class geChannelMode;
 class geButton;
 
@@ -50,7 +50,7 @@ private:
 
 public:
 
-       geSampleChannel(int x, int y, int w, int h, SampleChannel* ch);
+       geSampleChannel(int x, int y, int w, int h, giada::m::SampleChannel* ch);
 
        void resize(int x, int y, int w, int h) override;
 
index 405daa55c5699f5e8dd84014583ce985b76f3243..c5d631725e7145b65081bd3514007f5cb8f1dbe8 100644 (file)
@@ -64,8 +64,8 @@ int geSampleChannelButton::handle(int e)
                        break;
                }
                case FL_PASTE: {
-                       geSampleChannel* gch = static_cast<geSampleChannel*>(parent());
-                       SampleChannel*   ch  = static_cast<SampleChannel*>(gch->ch);
+                       geSampleChannel*  gch = static_cast<geSampleChannel*>(parent());
+                       m::SampleChannel* ch  = static_cast<m::SampleChannel*>(gch->ch);
                        int result = c::channel::loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())));
                        if (result != G_RES_OK)
                                G_MainWin->keyboard->printChannelMessage(result);
index f61207d3ad77ef2ef401151cc5a488bffb49288d..3e83d2d219af0e62f24e9968571fdf8e01fc5993 100644 (file)
@@ -32,6 +32,9 @@
 #include "mainTransport.h"
 
 
+using namespace giada;
+
+
 geMainTransport::geMainTransport(int x, int y)
        : Fl_Group(x, y, 131, 25)
 {
@@ -66,35 +69,35 @@ geMainTransport::geMainTransport(int x, int y)
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::cb_rewind   (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_rewind(); }
-void geMainTransport::cb_play     (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_play(); }
-void geMainTransport::cb_recAction(Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_recAction(); }
-void geMainTransport::cb_recInput (Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_recInput(); }
-void geMainTransport::cb_metronome(Fl_Widget *v, void *p) { ((geMainTransport*)p)->__cb_metronome(); }
+void geMainTransport::cb_rewind   (Fl_Widget *v, void *p) { ((geMainTransport*)p)->cb_rewind(); }
+void geMainTransport::cb_play     (Fl_Widget *v, void *p) { ((geMainTransport*)p)->cb_play(); }
+void geMainTransport::cb_recAction(Fl_Widget *v, void *p) { ((geMainTransport*)p)->cb_recAction(); }
+void geMainTransport::cb_recInput (Fl_Widget *v, void *p) { ((geMainTransport*)p)->cb_recInput(); }
+void geMainTransport::cb_metronome(Fl_Widget *v, void *p) { ((geMainTransport*)p)->cb_metronome(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::__cb_rewind()
+void geMainTransport::cb_rewind()
 {
-       glue_rewindSeq(true);
+       c::transport::rewindSeq(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::__cb_play()
+void geMainTransport::cb_play()
 {
-       glue_startStopSeq(true);
+       c::transport::startStopSeq(true);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::__cb_recAction()
+void geMainTransport::cb_recAction()
 {
        using namespace giada::c::io;
        startStopActionRec(true);
@@ -104,7 +107,7 @@ void geMainTransport::__cb_recAction()
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::__cb_recInput()
+void geMainTransport::cb_recInput()
 {
        using namespace giada::c::io;
        startStopInputRec(true);
@@ -114,9 +117,9 @@ void geMainTransport::__cb_recInput()
 /* -------------------------------------------------------------------------- */
 
 
-void geMainTransport::__cb_metronome()
+void geMainTransport::cb_metronome()
 {
-       glue_startStopMetronome(true);
+       c::transport::startStopMetronome(true);
 }
 
 
index 7461df3a6a20c6547927780b4793de57bc8c9e58..cd9290948016ca6261add7be83c6780e816952e4 100644 (file)
@@ -50,12 +50,11 @@ private:
        static void cb_recAction(Fl_Widget *v, void *p);
        static void cb_recInput (Fl_Widget *v, void *p);
        static void cb_metronome(Fl_Widget *v, void *p);
-
-       inline void __cb_rewind   ();
-       inline void __cb_play     ();
-       inline void __cb_recAction();
-       inline void __cb_recInput ();
-       inline void __cb_metronome();
+       void cb_rewind   ();
+       void cb_play     ();
+       void cb_recAction();
+       void cb_recInput ();
+       void cb_metronome();
 
 public:
 
index 5b226a2ed7b040ca2a02156ae9729582276fe750..28ac2e6bc308b633caee2a02b319dea0bbd2b55e 100644 (file)
@@ -31,9 +31,9 @@
 
 #include <FL/Fl_Group.H>
 #include "../../core/midiDispatcher.h"
+#include "../../core/channel.h"
 
 
-class Channel;
 class gdMidiInputBase;
 class geMidiLearner;
 class geBox;
@@ -54,7 +54,7 @@ private:
        /* Channel it belongs to. Might be nullptr if the learner comes from the MIDI
        input master window. */
 
-       Channel* ch;
+       giada::m::Channel* ch;
 
        geBox* text;
        geButton* value;
@@ -72,9 +72,9 @@ public:
 
   struct cbData_t
   {
-               gdMidiInputBase* window;
-               geMidiLearner*   learner;
-               Channel*         channel;
+               gdMidiInputBase*   window;
+               geMidiLearner*     learner;
+               giada::m::Channel* channel;
        } cbData;
 
        /* param
@@ -83,7 +83,7 @@ public:
        uint32_t* param;
 
        geMidiLearner(int x, int y, int w, const char* l, 
-               giada::m::midiDispatcher::cb_midiLearn* cb, uint32_t* param, Channel* ch);
+               giada::m::midiDispatcher::cb_midiLearn* cb, uint32_t* param, giada::m::Channel* ch);
 
        void updateValue();
 };
index c2ad697fbe9c052ee3921e3901aed07b8d12cb3b..fcedf0fc692a0a8c1fffdb4a9e2b9ea2ebe42851 100644 (file)
@@ -51,7 +51,7 @@ using std::string;
 using namespace giada;
 
 
-gePluginElement::gePluginElement(gdPluginList* gdp, Plugin* p, int X, int Y, int W)
+gePluginElement::gePluginElement(gdPluginList* gdp, m::Plugin* p, int X, int Y, int W)
        : Fl_Group   (X, Y, W, 20), 
          m_parentWin(gdp), 
          m_plugin    (p)
index 317cd87485c0a93a1b523476a5750a6ee2321f2d..8409322db27fedb6853b3a8748dd159ca4eb2a32 100644 (file)
@@ -36,7 +36,6 @@
 
 
 class gdPluginList;
-class Plugin;
 class geIdButton;
 class geChoice;
 
@@ -45,8 +44,8 @@ class gePluginElement : public Fl_Group
 {
 private:
 
-       gdPluginList* m_parentWin;
-       Plugin*       m_plugin;
+       gdPluginList*     m_parentWin;
+       giada::m::Plugin* m_plugin;
 
        static void cb_removePlugin(Fl_Widget* v, void* p);
        static void cb_openPluginWindow(Fl_Widget* v, void* p);
@@ -70,7 +69,7 @@ public:
        geIdButton* shiftDown;
        geIdButton* remove;
 
-       gePluginElement(gdPluginList* gdp, Plugin* p, int x, int y, int w);
+       gePluginElement(gdPluginList* gdp, giada::m::Plugin* p, int x, int y, int w);
 };
 
 #endif
index edc804da4ef2164f84841bcb1bdec470cb7e6742..81bbb3dcf68afb895dc29b891e64b2f62bc37ee6 100644 (file)
 
 
 using std::string;
+using namespace giada;
 using namespace giada::c;
 
 
-gePluginParameter::gePluginParameter(int paramIndex, Plugin* p, int X, int Y, 
+gePluginParameter::gePluginParameter(int paramIndex, m::Plugin* p, int X, int Y, 
        int W, int labelWidth)
        : Fl_Group    (X, Y, W, G_GUI_UNIT), 
          m_paramIndex(paramIndex), 
index 140ab156449279323f612fa848c8687f33b18a72..e07c9407a488abb812042d4f1a15d5a9ab014936 100644 (file)
@@ -35,7 +35,6 @@
 #include <FL/Fl_Group.H>
 
 
-class Plugin;
 class geBox;
 class geSlider;
 
@@ -47,7 +46,7 @@ private:
        static const int VALUE_WIDTH = 100;
 
        int m_paramIndex;
-       Plugin* m_plugin;
+       giada::m::Plugin* m_plugin;
 
        geBox*    m_label;
        geSlider* m_slider;
@@ -58,7 +57,7 @@ private:
 
 public:
 
-       gePluginParameter(int paramIndex, Plugin* p, int x, int y, int w, int labelWidth);
+       gePluginParameter(int paramIndex, giada::m::Plugin* p, int x, int y, int w, int labelWidth);
 
        void update(bool changeSlider);
 };
index 624658d601c9c701c3d7597dffb088bbf4a8517b..284b3f416368af8782334709bcf5e5071ffa710f 100644 (file)
 #include "boostTool.h"
 
 
-geBoostTool::geBoostTool(int X, int Y, SampleChannel* ch)
+using namespace giada;
+
+
+geBoostTool::geBoostTool(int X, int Y, m::SampleChannel* ch)
   : Fl_Group(X, Y, 220, 20),
     ch      (ch)
 {
index 1dc2d7cd9fc2ccf08a53ea7b5bbab6526f194bb6..a922a6edd535b0587f5881dfa70fe65b34c04810 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geDial;
 class geInput;
 class geButton;
@@ -43,25 +42,25 @@ class geBoostTool : public Fl_Group
 {
 private:
 
-  SampleChannel* ch;
+       giada::m::SampleChannel* ch;
 
-  geBox*    label;
-  geDial*   dial;
-  geInput*  input;
-  geButton* normalize;
+       geBox*    label;
+       geDial*   dial;
+       geInput*  input;
+       geButton* normalize;
 
-  static void cb_setBoost(Fl_Widget* w, void* p);
-  static void cb_setBoostNum(Fl_Widget* w, void* p);
-  static void cb_normalize(Fl_Widget* w, void* p);
-  inline void cb_setBoost();
-  inline void cb_setBoostNum();
-  inline void cb_normalize();
+       static void cb_setBoost(Fl_Widget* w, void* p);
+       static void cb_setBoostNum(Fl_Widget* w, void* p);
+       static void cb_normalize(Fl_Widget* w, void* p);
+       void cb_setBoost();
+       void cb_setBoostNum();
+       void cb_normalize();
 
 public:
 
-  geBoostTool(int x, int y, SampleChannel* ch);
+       geBoostTool(int x, int y, giada::m::SampleChannel* ch);
 
-  void refresh();
+       void refresh();
 };
 
 
index 29e4530fc6f77bbeedbc173001f14a21a2be4318..e9478a88ce82a5bc1e0017db2deccd0103de4913 100644 (file)
@@ -46,7 +46,7 @@ using std::string;
 using namespace giada;
 
 
-gePanTool::gePanTool(int x, int y, SampleChannel *ch)
+gePanTool::gePanTool(int x, int y, m::SampleChannel* ch)
   : Fl_Group(x, y, 200, 20),
     ch      (ch)
 {
@@ -94,15 +94,15 @@ void gePanTool::refresh()
 /* -------------------------------------------------------------------------- */
 
 
-void gePanTool::cb_panning (Fl_Widget *w, void *p) { ((gePanTool*)p)->__cb_panning(); }
-void gePanTool::cb_panReset(Fl_Widget *w, void *p) { ((gePanTool*)p)->__cb_panReset(); }
+void gePanTool::cb_panning (Fl_Widget *w, void *p) { ((gePanTool*)p)->cb_panning(); }
+void gePanTool::cb_panReset(Fl_Widget *w, void *p) { ((gePanTool*)p)->cb_panReset(); }
 
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gePanTool::__cb_panning()
+void gePanTool::cb_panning()
 {
   c::channel::setPanning(ch, dial->value());
 }
@@ -111,7 +111,7 @@ void gePanTool::__cb_panning()
 /* -------------------------------------------------------------------------- */
 
 
-void gePanTool::__cb_panReset()
+void gePanTool::cb_panReset()
 {
   c::channel::setPanning(ch, 0.5f);
 }
\ No newline at end of file
index e9d0cf66424c158e6e707564359022462237f6ed..fd485f50f749f6dbe8261c53890e291ed6e16de2 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geDial;
 class geInput;
 class geButton;
@@ -43,21 +42,21 @@ class gePanTool : public Fl_Group
 {
 private:
 
-  SampleChannel *ch;
+  giada::m::SampleChannel* ch;
 
-  geBox    *label;
-  geDial   *dial;
-  geInput  *input;
-  geButton *reset;
+  geBox*    label;
+  geDial*   dial;
+  geInput*  input;
+  geButtonreset;
 
-  static void cb_panning (Fl_Widget *w, void *p);
-  static void cb_panReset(Fl_Widget *w, void *p);
-  inline void __cb_panning();
-  inline void __cb_panReset();
+  static void cb_panning (Fl_Widget* w, void* p);
+  static void cb_panReset(Fl_Widget* w, void* p);
+  void cb_panning();
+  void cb_panReset();
 
 public:
 
-  gePanTool(int x, int y, SampleChannel *ch);
+  gePanTool(int x, int y, giada::m::SampleChannel* ch);
 
   void refresh();
 };
index 0cc1e47174a799ba289f3a5ce453bb2f1460df8c..e5eac55503f4ade73acafeff2895bd1ea00dc167 100644 (file)
@@ -44,7 +44,7 @@
 using namespace giada;
 
 
-gePitchTool::gePitchTool(int x, int y, SampleChannel* ch)
+gePitchTool::gePitchTool(int x, int y, m::SampleChannel* ch)
   : Fl_Group(x, y, 600, 20),
     ch      (ch)
 {
@@ -90,19 +90,19 @@ void gePitchTool::refresh()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::cb_setPitch      (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitch(); }
-void gePitchTool::cb_setPitchToBar (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToBar(); }
-void gePitchTool::cb_setPitchToSong(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToSong(); }
-void gePitchTool::cb_setPitchHalf  (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchHalf(); }
-void gePitchTool::cb_setPitchDouble(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchDouble(); }
-void gePitchTool::cb_resetPitch    (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_resetPitch(); }
-void gePitchTool::cb_setPitchNum   (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchNum(); }
+void gePitchTool::cb_setPitch      (Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitch(); }
+void gePitchTool::cb_setPitchToBar (Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitchToBar(); }
+void gePitchTool::cb_setPitchToSong(Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitchToSong(); }
+void gePitchTool::cb_setPitchHalf  (Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitchHalf(); }
+void gePitchTool::cb_setPitchDouble(Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitchDouble(); }
+void gePitchTool::cb_resetPitch    (Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_resetPitch(); }
+void gePitchTool::cb_setPitchNum   (Fl_Widget* w, void* p) { ((gePitchTool*)p)->cb_setPitchNum(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitch()
+void gePitchTool::cb_setPitch()
 {
   c::channel::setPitch(ch, dial->value());
 }
@@ -111,7 +111,7 @@ void gePitchTool::__cb_setPitch()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitchNum()
+void gePitchTool::cb_setPitchNum()
 {
   c::channel::setPitch(ch, atof(input->value()));
 }
@@ -120,7 +120,7 @@ void gePitchTool::__cb_setPitchNum()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitchHalf()
+void gePitchTool::cb_setPitchHalf()
 {
   c::channel::setPitch(ch, dial->value()/2);
 }
@@ -129,7 +129,7 @@ void gePitchTool::__cb_setPitchHalf()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitchDouble()
+void gePitchTool::cb_setPitchDouble()
 {
   c::channel::setPitch(ch, dial->value()*2);
 }
@@ -138,7 +138,7 @@ void gePitchTool::__cb_setPitchDouble()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitchToBar()
+void gePitchTool::cb_setPitchToBar()
 {
   // TODO - opaque channel's count
   c::channel::setPitch(ch, (ch->getEnd()) / (float) m::clock::getFramesInBar());
@@ -148,7 +148,7 @@ void gePitchTool::__cb_setPitchToBar()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_setPitchToSong()
+void gePitchTool::cb_setPitchToSong()
 {
   // TODO - opaque channel's count
   c::channel::setPitch(ch, ch->getEnd() / (float) m::clock::getFramesInLoop());
@@ -158,7 +158,7 @@ void gePitchTool::__cb_setPitchToSong()
 /* -------------------------------------------------------------------------- */
 
 
-void gePitchTool::__cb_resetPitch()
+void gePitchTool::cb_resetPitch()
 {
   c::channel::setPitch(ch, G_DEFAULT_PITCH);
 }
index 7ff9562cbbd5cb466d0a7e6ab87b7377df5a64bd..0ccfcdf9e7fe11a640a6170384fde225f31d56d3 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geDial;
 class geInput;
 class geButton;
@@ -43,35 +42,35 @@ class gePitchTool : public Fl_Group
 {
 private:
 
-  SampleChannel *ch;
-
-  geBox    *label;
-  geDial   *dial;
-  geInput  *input;
-  geButton *pitchToBar;
-  geButton *pitchToSong;
-  geButton *pitchHalf;
-  geButton *pitchDouble;
-  geButton *pitchReset;
-
-  static void cb_setPitch      (Fl_Widget *w, void *p);
-  static void cb_setPitchToBar (Fl_Widget *w, void *p);
-  static void cb_setPitchToSong(Fl_Widget *w, void *p);
-  static void cb_setPitchHalf  (Fl_Widget *w, void *p);
-  static void cb_setPitchDouble(Fl_Widget *w, void *p);
-  static void cb_resetPitch    (Fl_Widget *w, void *p);
-  static void cb_setPitchNum   (Fl_Widget *w, void *p);
-  inline void __cb_setPitch();
-  inline void __cb_setPitchToBar();
-  inline void __cb_setPitchToSong();
-  inline void __cb_setPitchHalf();
-  inline void __cb_setPitchDouble();
-  inline void __cb_resetPitch();
-  inline void __cb_setPitchNum();
+  giada::m::SampleChannel* ch;
+
+  geBox*    label;
+  geDial*   dial;
+  geInput*  input;
+  geButtonpitchToBar;
+  geButtonpitchToSong;
+  geButtonpitchHalf;
+  geButtonpitchDouble;
+  geButtonpitchReset;
+
+  static void cb_setPitch      (Fl_Widget* w, void* p);
+  static void cb_setPitchToBar (Fl_Widget* w, void* p);
+  static void cb_setPitchToSong(Fl_Widget* w, void* p);
+  static void cb_setPitchHalf  (Fl_Widget* w, void* p);
+  static void cb_setPitchDouble(Fl_Widget* w, void* p);
+  static void cb_resetPitch    (Fl_Widget* w, void* p);
+  static void cb_setPitchNum   (Fl_Widget* w, void* p);
+  void cb_setPitch();
+  void cb_setPitchToBar();
+  void cb_setPitchToSong();
+  void cb_setPitchHalf();
+  void cb_setPitchDouble();
+  void cb_resetPitch();
+  void cb_setPitchNum();
 
 public:
 
-  gePitchTool(int x, int y, SampleChannel *ch);
+  gePitchTool(int x, int y, giada::m::SampleChannel* ch);
 
   void refresh();
 };
index 88aa05d33f59cffe6ac0caba4fb1ad44a8f4948b..7dae165248a2fc5a440c49f88fbdd4120a873195 100644 (file)
@@ -43,7 +43,7 @@
 using namespace giada::c;
 
 
-geRangeTool::geRangeTool(int x, int y, SampleChannel* ch)
+geRangeTool::geRangeTool(int x, int y, giada::m::SampleChannel* ch)
        : Fl_Group(x, y, 280, G_GUI_UNIT),
                m_ch    (ch)
 {
@@ -81,14 +81,14 @@ void geRangeTool::refresh()
 /* -------------------------------------------------------------------------- */
 
 
-void geRangeTool::cb_setChanPos   (Fl_Widget* w, void* p) { ((geRangeTool*)p)->__cb_setChanPos(); }
-void geRangeTool::cb_resetStartEnd(Fl_Widget* w, void* p) { ((geRangeTool*)p)->__cb_resetStartEnd(); }
+void geRangeTool::cb_setChanPos   (Fl_Widget* w, void* p) { ((geRangeTool*)p)->cb_setChanPos(); }
+void geRangeTool::cb_resetStartEnd(Fl_Widget* w, void* p) { ((geRangeTool*)p)->cb_resetStartEnd(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geRangeTool::__cb_setChanPos()
+void geRangeTool::cb_setChanPos()
 {
        sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
        static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform(); // TODO - glue's business!
@@ -98,7 +98,7 @@ void geRangeTool::__cb_setChanPos()
 /* -------------------------------------------------------------------------- */
 
 
-void geRangeTool::__cb_resetStartEnd()
+void geRangeTool::cb_resetStartEnd()
 {
        sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
        static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform(); // TODO - glue's business!
index 17dcf7fc395e7ca74149a274526bc232e569fdf3..69efdfa6d8bfa3a181be0877488fdc1094f31648 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geInput;
 class geButton;
 class geBox;
@@ -42,7 +41,7 @@ class geRangeTool : public Fl_Group
 {
 private:
 
-  SampleChannel* m_ch;
+  giada::m::SampleChannel* m_ch;
 
   geBox*    m_label;
   geInput*  m_begin;
@@ -51,12 +50,12 @@ private:
 
   static void cb_setChanPos   (Fl_Widget* w, void* p);
   static void cb_resetStartEnd(Fl_Widget* w, void* p);
-  inline void __cb_setChanPos();
-  inline void __cb_resetStartEnd();
+  void cb_setChanPos();
+  void cb_resetStartEnd();
 
 public:
 
-  geRangeTool(int x, int y, SampleChannel* ch);
+  geRangeTool(int x, int y, giada::m::SampleChannel* ch);
 
   void refresh();
 };
index 5f0a2f8d3cf8defedf3f0de0b12f5323e8311a2b..0ab12c0f1f688b1eca1feb31fc42047ab46b40ee 100644 (file)
@@ -41,7 +41,7 @@
 using namespace giada::c;
 
 
-geShiftTool::geShiftTool(int x, int y, SampleChannel* ch)
+geShiftTool::geShiftTool(int x, int y, giada::m::SampleChannel* ch)
        : Fl_Group(x, y, 300, G_GUI_UNIT),
                m_ch    (ch)
 {
index 794ddc3a88e980b4e41f305bdb12f26c51a778ee..0b1a6d379c147ca826891419ff7fcb797989ce72 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geInput;
 class geButton;
 class geBox;
@@ -42,7 +41,7 @@ class geShiftTool : public Fl_Group
 {
 private:
 
-       SampleChannel* m_ch;
+       giada::m::SampleChannel* m_ch;
 
        geBox*    m_label;
        geInput*  m_shift;
@@ -57,7 +56,7 @@ private:
 
 public:
 
-       geShiftTool(int x, int y, SampleChannel* ch);
+       geShiftTool(int x, int y, giada::m::SampleChannel* ch);
 
        void refresh();
 };
index 4176150ab1cbe3f1739649d07eab122948bafaa9..d937c9cb4b04fa1fa9c1f4450acc269a75862f96 100644 (file)
 
 
 using std::string;
+using namespace giada;
 
 
-geVolumeTool::geVolumeTool(int X, int Y, SampleChannel* ch)
+geVolumeTool::geVolumeTool(int X, int Y, m::SampleChannel* ch)
   : Fl_Group(X, Y, 150, 20),
     ch      (ch)
 {
@@ -82,14 +83,14 @@ void geVolumeTool::refresh()
 /* -------------------------------------------------------------------------- */
 
 
-void geVolumeTool::cb_setVolume   (Fl_Widget* w, void* p) { ((geVolumeTool*)p)->__cb_setVolume(); }
-void geVolumeTool::cb_setVolumeNum(Fl_Widget* w, void* p) { ((geVolumeTool*)p)->__cb_setVolumeNum(); }
+void geVolumeTool::cb_setVolume   (Fl_Widget* w, void* p) { ((geVolumeTool*)p)->cb_setVolume(); }
+void geVolumeTool::cb_setVolumeNum(Fl_Widget* w, void* p) { ((geVolumeTool*)p)->cb_setVolumeNum(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geVolumeTool::__cb_setVolume()
+void geVolumeTool::cb_setVolume()
 {
   using namespace giada;
 
@@ -101,7 +102,7 @@ void geVolumeTool::__cb_setVolume()
 /* -------------------------------------------------------------------------- */
 
 
-void geVolumeTool::__cb_setVolumeNum()
+void geVolumeTool::cb_setVolumeNum()
 {
   using namespace giada;
 
index c526511564775f1cc3792d20fcc34b9919248684..b38323c38fcd0e9b65b8a931aed8b65dcb57ac19 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Group.H>
 
 
-class SampleChannel;
 class geDial;
 class geInput;
 class geBox;
@@ -42,20 +41,20 @@ class geVolumeTool : public Fl_Group
 {
 private:
 
-  SampleChannel *ch;
+  giada::m::SampleChannel* ch;
 
-  geBox   *label;
-  geDial  *dial;
-  geInput *input;
+  geBox*   label;
+  geDial*  dial;
+  geInputinput;
 
-  static void cb_setVolume   (Fl_Widget *w, void *p);
-       static void cb_setVolumeNum(Fl_Widget *w, void *p);
-  inline void __cb_setVolume   ();
-  inline void __cb_setVolumeNum();
+  static void cb_setVolume   (Fl_Widget* w, void* p);
+       static void cb_setVolumeNum(Fl_Widget* w, void* p);
+  void cb_setVolume   ();
+  void cb_setVolumeNum();
 
 public:
 
-  geVolumeTool(int x, int y, SampleChannel *ch);
+  geVolumeTool(int x, int y, giada::m::SampleChannel* ch);
 
   void refresh();
 };
index 7fdc453646a28da9fb4f6ef9c3e3730ef262e85a..622bb2cbd370b9f53893183d5c7b9d594faf998a 100644 (file)
@@ -115,7 +115,7 @@ void menuCallback(Fl_Widget* w, void* v)
 /* -------------------------------------------------------------------------- */
 
 
-geWaveTools::geWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l)
+geWaveTools::geWaveTools(int x, int y, int w, int h, m::SampleChannel* ch, const char* l)
        : Fl_Scroll(x, y, w, h, l),
                ch       (ch)
 {
@@ -236,13 +236,13 @@ void geWaveTools::openMenu()
                menu[(int)Menu::TO_NEW_CHANNEL].deactivate();           
        }
 
-       Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+       Fl_Menu_Buttonb = new Fl_Menu_Button(0, 0, 100, 50);
        b->box(G_CUSTOM_BORDER_BOX);
        b->textsize(G_GUI_FONT_SIZE_BASE);
        b->textcolor(G_COLOR_LIGHT_2);
        b->color(G_COLOR_GREY_2);
 
-       const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+       const Fl_Menu_Itemm = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
        if (m)
                m->do_callback(this, m->user_data());
        return;
index d352d388e5037afe7e7d528849498c354c2fb79f..b224c5318176d728fcc223c32d0e276d014a0dec 100644 (file)
@@ -32,7 +32,6 @@
 #include <FL/Fl_Scroll.H>
 
 
-class SampleChannel;
 class geWaveform;
 
 
@@ -44,10 +43,10 @@ private:
 
 public:
 
-       SampleChannel *ch;
-       geWaveform *waveform;
+       giada::m::SampleChannel* ch;
+       geWaveformwaveform;
 
-       geWaveTools(int X,int Y,int W, int H, SampleChannel *ch, const char *L=0);
+       geWaveTools(int x, int y, int w, int h, giada::m::SampleChannel* ch, const char* l=0);
        void resize(int x, int y, int w, int h);
        int  handle(int e);
 
index 7e3c4470b6571aa5657a19f37fc8ea3fed4b4243..5b1b77f7101ad7441c13991b1a078936d2e338b2 100644 (file)
@@ -48,7 +48,7 @@ using namespace giada::m;
 using namespace giada::c;
 
 
-geWaveform::geWaveform(int x, int y, int w, int h, SampleChannel* ch, const char* l)
+geWaveform::geWaveform(int x, int y, int w, int h, giada::m::SampleChannel* ch, const char* l)
 : Fl_Widget     (x, y, w, h, l),
        m_selection   {},
        m_ch          (ch),
index 05faaea684f6c1f41433d2caee97b5fd1045b965..1e7b426a4af57b21d6ebce4837855fb81ce5fabb 100644 (file)
@@ -33,9 +33,6 @@
 #include <FL/Fl_Widget.H>
 
 
-class SampleChannel;
-
-
 class geWaveform : public Fl_Widget
 {
 private:
@@ -71,7 +68,7 @@ private:
                std::vector<int> points;
        } m_grid;
 
-       SampleChannel* m_ch;
+       giada::m::SampleChannel* m_ch;
        int m_chanStart;
        bool m_chanStartLit;
        int m_chanEnd;
@@ -137,7 +134,7 @@ public:
        static const int ZOOM_IN  = -1;
        static const int ZOOM_OUT = 0;
 
-       geWaveform(int x, int y, int w, int h, SampleChannel* ch, const char* l=0);
+       geWaveform(int x, int y, int w, int h, giada::m::SampleChannel* ch, const char* l=0);
        ~geWaveform();
 
        void draw() override;
index b078fea45fe005f9593904b47fce3e1cb5d657ef..036fc0a1d1cace212386e59aa4e0530340a5c559 100644 (file)
 using namespace giada::m;
 
 
-geSoundMeter::geSoundMeter(int x, int y, int w, int h, const char *L)
-  : Fl_Box    (x, y, w, h, L),
-    clip      (false),
-    mixerPeak (0.0f),
-    peak      (0.0f),
-    dbLevel   (0.0f),
-    dbLevelOld(0.0f)
+geSoundMeter::geSoundMeter(int x, int y, int w, int h, const char* l)
+: Fl_Box    (x, y, w, h, l),
+       clip      (false),
+       mixerPeak (0.0f),
+       peak      (0.0f),
+       dbLevel   (0.0f),
+       dbLevelOld(0.0f)
 {
 }
 
@@ -51,37 +51,37 @@ geSoundMeter::geSoundMeter(int x, int y, int w, int h, const char *L)
 
 void geSoundMeter::draw()
 {
-  fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);
+       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);
 
-  /* peak = the highest value inside the frame */
+       /* peak = the highest value inside the frame */
 
-  peak = 0.0f;
-  float tmp_peak = 0.0f;
+       peak = 0.0f;
+       float tmp_peak = 0.0f;
 
-  tmp_peak = fabs(mixerPeak);
-  if (tmp_peak > peak)
-    peak = tmp_peak;
+       tmp_peak = fabs(mixerPeak);
+       if (tmp_peak > peak)
+               peak = tmp_peak;
 
-  clip = peak >= 1.0f ? true : false; // 1.0f is considered clip
+       clip = peak >= 1.0f ? true : false; // 1.0f is considered clip
 
 
-  /*  dBFS (full scale) calculation, plus decay of -2dB per frame */
+       /*  dBFS (full scale) calculation, plus decay of -2dB per frame */
 
-  dbLevel = 20 * log10(peak);
-  if (dbLevel < dbLevelOld)
-    if (dbLevelOld > -G_MIN_DB_SCALE)
-      dbLevel = dbLevelOld - 2.0f;
+       dbLevel = 20 * log10(peak);
+       if (dbLevel < dbLevelOld)
+               if (dbLevelOld > -G_MIN_DB_SCALE)
+                       dbLevel = dbLevelOld - 2.0f;
 
-  dbLevelOld = dbLevel;
+       dbLevelOld = dbLevel;
 
-  /* graphical part */
+       /* graphical part */
 
-  float px_level = 0.0f;
-  if (dbLevel < 0.0f)
-    px_level = ((w()/G_MIN_DB_SCALE) * dbLevel) + w();
-  else
-    px_level = w();
+       float px_level = 0.0f;
+       if (dbLevel < 0.0f)
+               px_level = ((w()/G_MIN_DB_SCALE) * dbLevel) + w();
+       else
+               px_level = w();
 
-  fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);
-  fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !kernelAudio::getStatus() ? G_COLOR_RED_ALERT : G_COLOR_GREY_4);
+       fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);
+       fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !kernelAudio::getStatus() ? G_COLOR_RED_ALERT : G_COLOR_GREY_4);
 }
index 649f106e813a6adf635a7217ac27bdf98aa4ecfc..02de14e6f8a396e0eb21cd5e051386e83b62b19c 100644 (file)
@@ -36,11 +36,11 @@ class geSoundMeter : public Fl_Box
 {
 public:
 
-  geSoundMeter(int X, int Y, int W, int H, const char *L=0);
+       geSoundMeter(int x, int y, int w, int h, const char* l=0);
 
-  void draw() override;
+       void draw() override;
 
-  bool clip;
+       bool clip;
        float mixerPeak;        // peak from mixer
 
 private:
index cfa9e3288584708886d0ee5340be520e1a994cf3..ec809d9ac06d0229df50bbd74a6c7b4308c7f5bf 100644 (file)
  * -------------------------------------------------------------------------- */
 
 
-#include <pthread.h>
-#if defined(__linux__) || defined(__APPLE__)
-       #include <unistd.h>
-#endif
+#include <atomic>
 #include <FL/Fl.H>
 #include "core/init.h"
-#include "core/const.h"
-#include "core/patch.h"
-#include "core/conf.h"
-#include "core/midiMapConf.h"
-#include "core/mixer.h"
-#include "core/clock.h"
-#include "core/mixerHandler.h"
-#include "core/kernelAudio.h"
-#include "core/kernelMidi.h"
-#include "core/recorder.h"
-#include "utils/gui.h"
-#include "utils/time.h"
-#include "gui/dialogs/gd_mainWindow.h"
-#include "core/pluginHost.h"
 
 
-pthread_t     G_videoThread;
-bool          G_quit;
-gdMainWindow* G_MainWin;
-
-
-void* videoThreadCb(void* arg);
+std::atomic<bool> G_quit(false);
+class gdMainWindow* G_MainWin = nullptr;
 
 
 int main(int argc, char** argv)
 {
-       G_quit = false;
-
-       init_prepareParser();
-       init_prepareMidiMap();
-       init_prepareKernelAudio();
-       init_prepareKernelMIDI();
-       init_startGUI(argc, argv);
-
-  Fl::lock();
-       pthread_create(&G_videoThread, nullptr, videoThreadCb, nullptr);
-       init_startKernelAudio();
+       using namespace giada;
 
-#ifdef WITH_VST
-       juce::initialiseJuce_GUI();
-#endif
+       m::init::startup(argc, argv);
 
        int ret = Fl::run();
 
-#ifdef WITH_VST
-       juce::shutdownJuce_GUI();
-#endif
+       m::init::shutdown();
 
-       pthread_join(G_videoThread, nullptr);
        return ret;
 }
 
 
-void* videoThreadCb(void* arg)
-{
-       using namespace giada;
 
-       if (m::kernelAudio::getStatus())
-               while (!G_quit) {
-                       gu_refreshUI();
-                       u::time::sleep(G_GUI_REFRESH_RATE);
-               }
-       pthread_exit(nullptr);
-       return 0;
-}
index 16e6f9f83b6abc4d91be89cb94a96d4d150ea9aa..174978ae501494b4ac2d682a88a1c70671833e2a 100644 (file)
@@ -41,12 +41,18 @@ int quantize(int x, int step);
 Maps 'x' in range [a, b] to a new range [w, z]. Source:
        https://en.wikipedia.org/wiki/Linear_equation#Two-point_form*/
 
-template <typename Tin, typename Tout>
-Tout map(Tin x, Tin a, Tin b, Tout w, Tout z)
+template <typename TI, typename TO>
+TO map(TI x, TI a, TI b, TO w, TO z)
 {
        return (((x - a) / (float) (b - a)) * (z - w)) + w;
 }
 
+
+template <typename T>
+T bound(T x, T min, T max, T def)
+{
+    return x < min || x > max ? def : x;
+}
 }}}  // giada::u::math::
 
 
index daf869c37397805208e30ce9ee748cdfeca64a66..b9d14993638aef3714cc4b167f30b84417c242e9 100644 (file)
@@ -42,7 +42,6 @@ TEST_CASE("AudioBuffer")
 
                buffer.free();
 
-               REQUIRE(buffer[0] == nullptr);
                REQUIRE(buffer.countFrames() == 0);
                REQUIRE(buffer.countSamples() == 0);
                REQUIRE(buffer.countChannels() == 0);
index c392b812ca9637c7ab4d0ba9068be2f806f7fbe6..00418d523754a9a164a0b7e3704a9623318f7577 100644 (file)
@@ -44,7 +44,6 @@ TEST_CASE("conf")
     conf::recsStopOnChanHalt = true;
     conf::chansStopOnSeqHalt = false;
     conf::treatRecsAsLoops = true;
-    conf::resizeRecordings = false;
     conf::pluginPath = "path/to/plugins";
     conf::patchPath = "path/to/patches";
     conf::samplePath = "path/to/samples";
@@ -119,7 +118,6 @@ TEST_CASE("conf")
     REQUIRE(conf::recsStopOnChanHalt == true);
     REQUIRE(conf::chansStopOnSeqHalt == false);
     REQUIRE(conf::treatRecsAsLoops == true);
-    REQUIRE(conf::resizeRecordings == false);
     REQUIRE(conf::pluginPath == "path/to/plugins");
     REQUIRE(conf::patchPath == "path/to/patches");
     REQUIRE(conf::samplePath == "path/to/samples");
index 3c52f4efe850006e4b4951daac18f3726284a551..59f7b39f9246f2dec0067467280e9a05a3ee7611 100644 (file)
@@ -26,14 +26,18 @@ TEST_CASE("patch")
                patch::plugin_t  plugin3;
 #endif
 
-               action0.type   = 0;
-               action0.frame  = 50000;
-               action0.fValue = 0.3f;
-               action0.iValue = 1000;
-               action1.type   = 2;
-               action1.frame  = 589;
-               action1.fValue = 1.0f;
-               action1.iValue = 130;
+               action0.id      = 0;
+               action0.channel = 6;
+               action0.frame   = 4000;
+               action0.event   = 0xFF00FF00;
+               action0.prev    = -1;
+               action0.next    = -1;
+               action1.id      = 1;
+               action1.channel = 2;
+               action1.frame   = 8000;
+               action1.event   = 0x00000000;
+               action1.prev    = -1;
+               action1.next    = -1;
                channel1.actions.push_back(action0);
                channel1.actions.push_back(action1);
 
@@ -179,16 +183,20 @@ TEST_CASE("patch")
                REQUIRE(channel0.midiOutChan == 5);
 
                patch::action_t action0 = channel0.actions.at(0);
-               REQUIRE(action0.type == 0);
-               REQUIRE(action0.frame == 50000);
-               REQUIRE(action0.fValue == Approx(0.3f));
-               REQUIRE(action0.iValue == 1000);
+               REQUIRE(action0.id == 0);
+               REQUIRE(action0.channel == 6);
+               REQUIRE(action0.frame == 4000);
+               REQUIRE(action0.event == 0xFF00FF00);
+               REQUIRE(action0.prev == -1);
+               REQUIRE(action0.next == -1);
 
                patch::action_t action1 = channel0.actions.at(1);
-               REQUIRE(action1.type == 2);
-               REQUIRE(action1.frame == 589);
-               REQUIRE(action1.fValue == Approx(1.0f));
-               REQUIRE(action1.iValue == 130);
+               REQUIRE(action1.id == 1);
+               REQUIRE(action1.channel == 2);
+               REQUIRE(action1.frame == 8000);
+               REQUIRE(action1.event == 0x00000000);
+               REQUIRE(action1.prev == -1);
+               REQUIRE(action1.next == -1);
 
 #ifdef WITH_VST
                patch::plugin_t plugin0 = channel0.plugins.at(0);
index 85deb8982e39441a9eb90c739565e7eb3f78eaf1..5cc6d4c23f39d22bcdf87316cb6d7eda0ebe5253 100644 (file)
 #include "../src/core/recorder.h"
 #include "../src/core/const.h"
+#include "../src/core/types.h"
+#include "../src/core/action.h"
 #include <catch.hpp>
 
 
-using std::string;
-using namespace giada::m;
-
-
 TEST_CASE("recorder")
 {
-       /* Each SECTION the TEST_CASE is executed from the start. The following
-       code is exectuted before each SECTION. */
+       using namespace giada;
+       using namespace giada::m;
 
        pthread_mutex_t mutex;
        pthread_mutex_init(&mutex, nullptr);
 
-       recorder::init();
-       REQUIRE(recorder::frames.size() == 0);
-       REQUIRE(recorder::global.size() == 0);
+       recorder::init(&mutex);
+       recorder::enable();
 
-       SECTION("Test record single action")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 50, 1, 0.5f);
-
-               REQUIRE(recorder::frames.size() == 1);
-               REQUIRE(recorder::frames.at(0) == 50);
-               REQUIRE(recorder::global.at(0).size() == 1);  // 1 action on frame #0
-               REQUIRE(recorder::global.at(0).at(0)->chan == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(0).at(0)->frame == 50);
-               REQUIRE(recorder::global.at(0).at(0)->iValue == 1);
-               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.5f);
-       }
+       REQUIRE(recorder::hasActions(/*ch=*/0) == false);
 
-       SECTION("Test record, two actions on same frame")
+       SECTION("Test record")
        {
-               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-               recorder::rec(0, G_ACTION_KEYREL,   50, 1, 0.5f);
+               const int       ch = 0;
+               const Frame     f1 = 10;
+               const Frame     f2 = 70;
+               const MidiEvent e1 = MidiEvent(MidiEvent::NOTE_ON, 0x00, 0x00);
+               const MidiEvent e2 = MidiEvent(MidiEvent::NOTE_OFF, 0x00, 0x00);
 
-               REQUIRE(recorder::frames.size() == 1);    // same frame, frames.size must stay 1
-               REQUIRE(recorder::frames.at(0) == 50);
-               REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
+               const Action* a1 = recorder::rec(ch, f1, e1);
+               const Action* a2 = recorder::rec(ch, f2, e2);
 
-               REQUIRE(recorder::global.at(0).at(0)->chan == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(0).at(0)->frame == 50);
-               REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
-               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
+               REQUIRE(recorder::hasActions(ch) == true);
+               REQUIRE(a1->frame == f1);
+               REQUIRE(a2->frame == f2);
+               REQUIRE(a1->prev == nullptr);
+               REQUIRE(a1->next == nullptr);
+               REQUIRE(a2->prev == nullptr);
+               REQUIRE(a2->next == nullptr);
 
-               REQUIRE(recorder::global.at(0).at(1)->chan == 0);
-               REQUIRE(recorder::global.at(0).at(1)->type == G_ACTION_KEYREL);
-               REQUIRE(recorder::global.at(0).at(1)->frame == 50);
-               REQUIRE(recorder::global.at(0).at(1)->iValue == 1);
-               REQUIRE(recorder::global.at(0).at(1)->fValue == 0.5f);
-
-               SECTION("Test record, another action on a different frame")
+               SECTION("Test clear actions by channel")
                {
-                       recorder::rec(0, G_ACTION_KEYPRESS, 70, 1, 0.5f);
-
-                       REQUIRE(recorder::frames.size() == 2);
-                       REQUIRE(recorder::frames.at(1) == 70);
-                       REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
-                       REQUIRE(recorder::global.at(1).size() == 1);  // 1 actions on frame #1
-                       REQUIRE(recorder::global.at(1).at(0)->chan == 0);
-                       REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYPRESS);
-                       REQUIRE(recorder::global.at(1).at(0)->frame == 70);
-                       REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
-                       REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
+                       const int       ch = 1;
+                       const Frame     f1 = 100;
+                       const Frame     f2 = 200;
+                       const MidiEvent e1 = MidiEvent(MidiEvent::NOTE_ON, 0x00, 0x00);
+                       const MidiEvent e2 = MidiEvent(MidiEvent::NOTE_OFF, 0x00, 0x00);
+
+                       recorder::rec(ch, f1, e1);
+                       recorder::rec(ch, f2, e2);
+
+                       recorder::clearChannel(/*channel=*/0);
+                       
+                       REQUIRE(recorder::hasActions(/*channel=*/0) == false);
+                       REQUIRE(recorder::hasActions(/*channel=*/1) == true);
                }
-       }
-
-       SECTION("Test retrieval")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-               recorder::rec(0, G_ACTION_KEYREL,   70, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   70, 1, 0.5f);
-               recorder::rec(2, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-               recorder::rec(2, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-               /* Give me action on chan 1, type G_ACTION_KEYREL, frame 70. */
-               recorder::action *action = nullptr;
-               REQUIRE(recorder::getAction(1, G_ACTION_KEYREL, 70, &action) == 1);
-
-               REQUIRE(action != nullptr);
-               REQUIRE(action->chan == 1);
-               REQUIRE(action->type == G_ACTION_KEYREL);
-               REQUIRE(action->frame == 70);
-               REQUIRE(action->iValue == 1);
-               REQUIRE(action->fValue == 0.5f);
-
-               /* Give me *next* action on chan 0, type G_ACTION_KEYREL, starting from frame 20.
-               Must be action #2 */
-
-               REQUIRE(recorder::getNextAction(0, G_ACTION_KEYREL, 20, &action) == 1);
-               REQUIRE(action != nullptr);
-               REQUIRE(action->chan == 0);
-               REQUIRE(action->type == G_ACTION_KEYREL);
-               REQUIRE(action->frame == 70);
-
-               /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
-               frame 200. You are requesting frame outside boundaries. */
-
-               REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 200, &action) == -1);
-
-               /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
-               frame 100. That action does not exist. */
 
-               REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 100, &action) == -2);
-       }
-
-       SECTION("Test retrieval MIDI")
-       {
-               recorder::rec(0, G_ACTION_MIDI, 0,    0x903C3F00, 0.0f);
-               recorder::rec(1, G_ACTION_MIDI, 0,    0x903D3F00, 0.0f);
-               recorder::rec(0, G_ACTION_MIDI, 1000, 0x803C2000, 0.0f);                
-               recorder::rec(0, G_ACTION_MIDI, 1050, 0x903C3F00, 0.0f);
-               recorder::rec(0, G_ACTION_MIDI, 2000, 0x803C3F00, 0.0f);
-               recorder::rec(1, G_ACTION_MIDI, 90,   0x803D3F00, 0.0f);                
-               recorder::rec(1, G_ACTION_MIDI, 1050, 0x903D3F00, 0.0f);
-               recorder::rec(1, G_ACTION_MIDI, 2000, 0x803D3F00, 0.0f);
-
-               recorder::action* result = nullptr;
-               recorder::getNextAction(0, G_ACTION_MIDI, 100, &result, 0x803CFF00, 0x0000FF00);
-
-               REQUIRE(result != nullptr);
-               REQUIRE(result->frame == 1000);
-       }
-
-       SECTION("Test deletion, single action")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-               recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 70, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-
-               /* Delete action #0, don't check values. */
-               recorder::deleteAction(0, 50, G_ACTION_KEYPRESS, false, &mutex);
-
-               REQUIRE(recorder::frames.size() == 3);
-               REQUIRE(recorder::global.size() == 3);
-
-               SECTION("Test deletion checked")
+               SECTION("Test clear actions by type")
                {
-                       /* Delete action #1, check values. */
-                       recorder::deleteAction(1, 70, G_ACTION_KEYPRESS, true, &mutex, 6, 0.3f);
-
-                       REQUIRE(recorder::frames.size() == 2);
-                       REQUIRE(recorder::global.size() == 2);
+                       recorder::clearActions(/*channel=*/0, MidiEvent::NOTE_ON);
+                       recorder::clearActions(/*channel=*/0, MidiEvent::NOTE_OFF);
+                       
+                       REQUIRE(recorder::hasActions(/*channel=*/0) == false);
                }
-       }
-
-       SECTION("Test deletion, range of actions")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-               recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS, 70, 6, 0.3f);
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-               /* Delete any action on channel 0 of types KEYPRESS | KEYREL between
-               frames 0 and 200. */
 
-               recorder::deleteActions(0, 0, 200, G_ACTION_KEYPRESS | G_ACTION_KEYREL, &mutex);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::global.size() == 2);
-               REQUIRE(recorder::global.at(0).size() == 1);
-               REQUIRE(recorder::global.at(1).size() == 1);
-
-               REQUIRE(recorder::global.at(0).at(0)->chan == 1);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(0).at(0)->frame == 100);
-               REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
-               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
-
-               REQUIRE(recorder::global.at(1).at(0)->chan == 1);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 120);
-               REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
-               REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
-       }
-
-       SECTION("Test action presence")
-       {
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-               recorder::deleteAction(0, 80, G_ACTION_KEYREL, false, &mutex);
-
-               REQUIRE(recorder::hasActions(0) == false);
-               REQUIRE(recorder::hasActions(1) == true);
-       }
-
-       SECTION("Test clear actions by channel")
-       {
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-               recorder::clearChan(1);
-
-               REQUIRE(recorder::hasActions(0) == true);
-               REQUIRE(recorder::hasActions(1) == false);
-               REQUIRE(recorder::frames.size() == 1);
-               REQUIRE(recorder::global.size() == 1);
-               REQUIRE(recorder::global.at(0).size() == 1);
-       }
-
-       SECTION("Test clear actions by type")
-       {
-               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-               /* Clear all actions of type KEYREL from channel 1. */
-
-               recorder::clearAction(1, G_ACTION_KEYREL);
-
-               REQUIRE(recorder::hasActions(0) == true);
-               REQUIRE(recorder::hasActions(1) == false);
-               REQUIRE(recorder::frames.size() == 1);
-               REQUIRE(recorder::global.size() == 1);
-               REQUIRE(recorder::global.at(0).size() == 1);
-       }
-
-       SECTION("Test clear all")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 0, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYREL,   100, 6, 0.3f);
-               recorder::rec(2, G_ACTION_KILL, 120, 1, 0.5f);
-
-               recorder::clearAll();
-               REQUIRE(recorder::frames.size() == 0);
-               REQUIRE(recorder::global.size() == 0);
-       }
-
-       SECTION("Test optimization")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS, 20, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYPRESS, 20, 1, 0.5f);
-               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-
-               /* Fake frame 80 without actions.*/
-               recorder::global.at(1).clear();
-
-               recorder::optimize();
-
-               REQUIRE(recorder::frames.size() == 1);
-               REQUIRE(recorder::global.size() == 1);
-               REQUIRE(recorder::global.at(0).size() == 2);
-       }
-
-       SECTION("Test BPM update")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,  0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
 
-               recorder::updateBpm(60.0f, 120.0f, 44100);  // scaling up
-
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 40);
-
-               recorder::updateBpm(120.0f, 60.0f, 44100);  // scaling down
-
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 80);
-       }
-
-       SECTION("Test samplerate update")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS, 120, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,   150, 1, 0.5f);
-
-               recorder::updateSamplerate(44100, 22050); // scaling down
-
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 160);
-               REQUIRE(recorder::frames.at(2) == 240);
-               REQUIRE(recorder::frames.at(3) == 300);
-
-               recorder::updateSamplerate(22050, 44100); // scaling up
-
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 80);
-               REQUIRE(recorder::frames.at(2) == 120);
-               REQUIRE(recorder::frames.at(3) == 150);
-       }
-
-       SECTION("Test expand")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
-
-               recorder::expand(300, 600);
-
-               REQUIRE(recorder::frames.size() == 6);
-               REQUIRE(recorder::global.size() == 6);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 80);
-               REQUIRE(recorder::frames.at(2) == 200);
-               REQUIRE(recorder::frames.at(3) == 300);
-               REQUIRE(recorder::frames.at(4) == 380);
-               REQUIRE(recorder::frames.at(5) == 500);
-       }
-
-       SECTION("Test shrink")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
-
-               recorder::shrink(100);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::global.size() == 2);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 80);
-       }
-       
-       SECTION("Test overdub, full overwrite")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL,  80, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS,  200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
-
-               /* Should delete all actions in between and keep the first one, plus a
-               new last action on frame 500. */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 1024);
-               recorder::stopOverdub(500, 500, &mutex);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::global.size() == 2);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 500);
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, left overlap")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,  100, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
-
-               /* Overdub part of the leftmost part of a composite action. Expected result:
-               a new composite action.
-               Original:    ----|########|
-               Overdub:     |#######|-----
-               Result:      |#######|----- */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 16);
-               recorder::stopOverdub(300, 500, &mutex);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::global.size() == 2);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 300);
-
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 300);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, right overlap")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,  000, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
-
-               /* Overdub part of the rightmost part of a composite action. Expected result:
-               a new composite action.
-               Original:    |########|------
-               Overdub:     -----|#######|--
-               Result:      |###||#######|-- */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 100, 16);
-               recorder::stopOverdub(500, 500, &mutex);
-
-               REQUIRE(recorder::frames.size() == 4);
-               REQUIRE(recorder::global.size() == 4);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
-               REQUIRE(recorder::frames.at(2) == 100);
-               REQUIRE(recorder::frames.at(3) == 500);
-
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-
-               REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(3).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, hole diggin'")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 400, 1, 0.5f);
-
-               /* Overdub in the middle of a long, composite action. Expected result:
-               original action trimmed down plus anther action next to it. Total frames
-               should be 4.
-               Original:    |#############|
-               Overdub:     ---|#######|---
-               Result:      |#||#######|--- */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 100, 16);
-               recorder::stopOverdub(300, 500, &mutex);
-
-               REQUIRE(recorder::frames.size() == 4);
-               REQUIRE(recorder::global.size() == 4);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
-               REQUIRE(recorder::frames.at(2) == 100);
-               REQUIRE(recorder::frames.at(3) == 300);
-
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-
-               REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(3).at(0)->frame == 300);
-               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, cover all")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 100, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS,  120, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYPRESS,  220, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 300, 1, 0.5f);
-
-               /* Overdub all existing actions. Expected result: a single composite one. */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 0, 16);
-               recorder::stopOverdub(500, 500, &mutex);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::global.size() == 2);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 500);
-
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, null loop")
-       {
-               recorder::rec(0, G_ACTION_KEYPRESS,    0, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 500, 1, 0.5f);
-
-               /* A null loop is a loop that begins and ends on the very same frame. */
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 300, 16);
-               recorder::stopOverdub(300, 700, &mutex);
-
-               REQUIRE(recorder::frames.size() == 2);
-               REQUIRE(recorder::frames.at(0) == 0);
-               REQUIRE(recorder::frames.at(1) == 284);  // 300 - bufferSize (16)
-
-               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-               REQUIRE(recorder::global.at(1).at(0)->frame == 284);
-               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-       }
-
-       SECTION("Test overdub, ring loop")
-       {
-               /* A ring loop occurs when you record the last action beyond the end of
-               the sequencer.
-               Original:    ---|#######|---
-               Overdub:     #####|------|##
-               Result:      ---|#######||#| */
-
-               recorder::rec(0, G_ACTION_KEYPRESS,  200, 1, 0.5f);
-               recorder::rec(0, G_ACTION_KEYREL, 300, 1, 0.5f);
-
-               recorder::startOverdub(0, G_ACTION_KEYPRESS | G_ACTION_KEYREL, 400, 16);
-               recorder::stopOverdub(250, 700, &mutex);
-
-               REQUIRE(recorder::frames.size() == 4);
-               REQUIRE(recorder::frames.at(0) == 200);
-               REQUIRE(recorder::frames.at(1) == 300);
-               REQUIRE(recorder::frames.at(2) == 400);
-               REQUIRE(recorder::frames.at(3) == 700);
+               SECTION("Test clear all")
+               {
+                       recorder::clearAll();
+                       REQUIRE(recorder::hasActions(/*channel=*/0) == false);
+               }
        }
-}
+}
\ No newline at end of file
index fe7eee3134f378d29a1c683e61e40c8c1d24da6f..59ecdbef0e38fe79c4e715371a8ddc26cf69ab4b 100644 (file)
@@ -29,7 +29,7 @@ TEST_CASE("sampleChannel")
                REQUIRE(ch.wave == w);
                REQUIRE(ch.begin == 0);
                REQUIRE(ch.end == w->getSize() - 1);
-               REQUIRE(ch.name == w->getBasename());           
+               REQUIRE(ch.name == "");         
        }
 
        SECTION("begin/end")