--------------------------------------------------------------------------------
+0.15.4 --- 2019 . 03 . 22
+- New record-on-signal option for input and action recording
+- Initial support for plug-ins with mono I/O buses
+- PluginHost refactoring
+- Smart pointers for Wave and Plugin objects
+- Remove old and deprecated input delay compensation
+- Optimized audio IO processing in Mixer callback
+- Atomic I/O meters with improved accuracy
+- Fix memory leak when replacing samples in a Sample Channel
+- Fix plug-ins ordering method when re-opening Giada
+- Fix silent Sample Channel when recording actions a second time
+- Fix velocity always discarded when sending key-press to Sample Channel
+- Fix inability to record actions with quantizer enabled
+
+
0.15.3 --- 2018 . 12 . 24
- Action recorder refactoring
- Optional midimap parameters (thank you @tomek-szczesny)
cppFlags =
-cxxFlags = -std=c++11 -Wall
+cxxFlags = -std=c++14 -Wall
ldAdd =
ldFlags =
sourcesExtra =
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/pluginManager.h \
+ src/core/pluginManager.cpp \
src/core/mixerHandler.h \
src/core/mixerHandler.cpp \
src/core/init.h \
src/core/sampleChannelRec.cpp \
src/core/midiChannelProc.h \
src/core/midiChannelProc.cpp \
+ src/core/recManager.h \
+ src/core/recManager.cpp \
src/glue/main.h \
src/glue/main.cpp \
src/glue/io.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 \
+ src/gui/dispatcher.h \
+ src/gui/dispatcher.cpp \
+ src/gui/dialogs/keyGrabber.h \
+ src/gui/dialogs/keyGrabber.cpp \
src/gui/dialogs/about.h \
src/gui/dialogs/about.cpp \
- src/gui/dialogs/gd_mainWindow.h \
- src/gui/dialogs/gd_mainWindow.cpp \
+ src/gui/dialogs/mainWindow.h \
+ src/gui/dialogs/mainWindow.cpp \
src/gui/dialogs/beatsInput.h \
src/gui/dialogs/beatsInput.cpp \
- src/gui/dialogs/gd_warnings.h \
- src/gui/dialogs/gd_warnings.cpp \
+ src/gui/dialogs/warnings.h \
+ src/gui/dialogs/warnings.cpp \
src/gui/dialogs/bpmInput.h \
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.cpp \
- src/gui/dialogs/gd_devInfo.h \
- src/gui/dialogs/gd_devInfo.cpp \
+ src/gui/dialogs/config.h \
+ src/gui/dialogs/config.cpp \
+ src/gui/dialogs/devInfo.h \
+ src/gui/dialogs/devInfo.cpp \
src/gui/dialogs/pluginList.h \
src/gui/dialogs/pluginList.cpp \
src/gui/dialogs/pluginWindow.h \
src/gui/elems/basics/statusButton.cpp \
src/gui/elems/basics/button.h \
src/gui/elems/basics/button.cpp \
- src/gui/elems/basics/idButton.h \
- src/gui/elems/basics/idButton.cpp \
src/gui/elems/basics/resizerBar.h \
src/gui/elems/basics/resizerBar.cpp \
src/gui/elems/basics/input.h \
src/utils/gvector.h \
src/utils/fs.h \
src/utils/fs.cpp \
+ src/utils/vector.h \
src/utils/ver.h \
src/utils/ver.cpp \
src/utils/string.h \
## Copyright
-Giada is Copyright (C) 2010-2018 by Giovanni A. Zuliani | Monocasual
+Giada is Copyright (C) 2010-2019 by Giovanni A. Zuliani | Monocasual
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.
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "const.h"
#include "channelManager.h"
#include "pluginHost.h"
+#include "pluginManager.h"
#include "plugin.h"
#include "kernelMidi.h"
#include "patch.h"
midiOutLsolo = src->midiOutLsolo;
#ifdef WITH_VST
- for (Plugin* plugin : src->plugins)
- pluginHost::clonePlugin(plugin, pluginHost::CHANNEL, pluginMutex, this);
+
+ for (const std::unique_ptr<Plugin>& plugin : src->plugins)
+ pluginHost::addPlugin(pluginManager::makePlugin(*plugin.get()),
+ pluginHost::StackType::CHANNEL, pluginMutex, this);
+
#endif
hasActions = recorderHandler::cloneActions(src->index, index);
#ifdef WITH_VST
-juce::MidiBuffer &Channel::getPluginMidiEvents()
+const juce::MidiBuffer& Channel::getPluginMidiEvents() const
{
return midiBuffer;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#ifdef WITH_VST
#include "../deps/juce-config.h"
+ #include "plugin.h"
#endif
namespace giada {
-namespace m
+namespace m
{
-class Plugin;
-
class Channel
{
public:
/* process
Merges working buffers into 'out', plus plugin processing (if any). Warning:
- inBuffer might be nullptr if no input devices are available for recording. */
+ inBuffer might be unallocated if no input devices are available for
+ recording. */
virtual void process(AudioBuffer& out, const AudioBuffer& in, bool audible,
bool running) = 0;
Midi channels, true for Sample channels only if they don't contain a
sample yet.*/
- virtual bool canInputRec() = 0;
-
+ virtual bool canInputRec() const { return false; };
virtual bool hasLogicalData() const { return false; };
virtual bool hasEditedData() const { return false; };
virtual bool hasData() const { return false; };
#ifdef WITH_VST
/* getPluginMidiEvents
- * Return a reference to midiBuffer stack. This is available for any kind of
- * channel, but it makes sense only for MIDI channels. */
+ Returns a reference to midiBuffer stack. This is available for any kind of
+ channel, but it makes sense only for MIDI channels. */
- juce::MidiBuffer& getPluginMidiEvents();
+ const juce::MidiBuffer& getPluginMidiEvents() const;
void clearMidiBuffer();
double volume_i;
double volume_d;
- bool hasActions; // has something recorded
- bool readActions; // read what's recorded
+ bool hasActions; // If has some actions recorded
+ bool readActions; // If should read recorded actions
bool midiIn; // enable midi input
uint32_t midiInKeyPress;
uint32_t midiOutLsolo;
#ifdef WITH_VST
- std::vector <Plugin*> plugins;
+ std::vector<std::unique_ptr<Plugin>> plugins;
#endif
protected:
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "sampleChannel.h"
#include "midiChannel.h"
#include "pluginHost.h"
+#include "pluginManager.h"
#include "plugin.h"
#include "action.h"
#include "recorderHandler.h"
{
#ifdef WITH_VST
- pluginHost::forEachPlugin(pluginHost::CHANNEL, ch, [&] (const Plugin* p) {
+ pluginHost::forEachPlugin(pluginHost::StackType::CHANNEL, ch, [&] (const Plugin* p) {
patch::plugin_t pp;
pp.path = p->getUniqueId();
pp.bypass = p->isBypassed();
#ifdef WITH_VST
for (const patch::plugin_t& ppl : pch.plugins) {
- Plugin* plugin = pluginHost::addPlugin(ppl.path, pluginHost::CHANNEL,
- &mixer::mutex, ch);
+
+ std::unique_ptr<Plugin> plugin = pluginManager::makePlugin(ppl.path);
if (plugin == nullptr)
continue;
for (uint32_t midiInParam : ppl.midiInParams)
plugin->midiInParams.push_back(midiInParam);
}
+
+ pluginHost::addPlugin(std::move(plugin), pluginHost::StackType::CHANNEL, &mixer::mutex, ch);
}
#endif
pch.begin = ch->getBegin();
pch.end = ch->getEnd();
pch.boost = ch->getBoost();
- pch.recActive = ch->readActions;
+ pch.readActions = ch->readActions;
pch.pitch = ch->getPitch();
pch.inputMonitor = ch->inputMonitor;
pch.midiInReadActions = ch->midiInReadActions;
void readPatch(SampleChannel* ch, const string& basePath, const patch::channel_t& pch)
{
ch->mode = static_cast<ChannelMode>(pch.mode);
- ch->readActions = pch.recActive;
- ch->recStatus = pch.recActive ? ChannelStatus::PLAY : ChannelStatus::OFF;
+ ch->readActions = pch.readActions;
+ ch->recStatus = pch.readActions ? ChannelStatus::PLAY : ChannelStatus::OFF;
ch->midiInVeloAsVol = pch.midiInVeloAsVol;
ch->midiInReadActions = pch.midiInReadActions;
ch->midiInPitch = pch.midiInPitch;
ch->inputMonitor = pch.inputMonitor;
ch->setBoost(pch.boost);
- Wave* w = nullptr;
- int res = waveManager::create(basePath + pch.samplePath, &w);
+ waveManager::Result res = waveManager::createFromFile(basePath + pch.samplePath);
- if (res == G_RES_OK) {
- ch->pushWave(w);
+ if (res.status == G_RES_OK) {
+ ch->pushWave(std::move(res.wave));
ch->setBegin(pch.begin);
ch->setEnd(pch.end);
ch->setPitch(pch.pitch);
}
else {
- if (res == G_RES_ERR_NO_DATA)
+ if (res.status == G_RES_ERR_NO_DATA)
ch->status = ChannelStatus::EMPTY;
else
- if (res == G_RES_ERR_IO)
+ if (res.status == G_RES_ERR_IO)
ch->status = ChannelStatus::MISSING;
ch->sendMidiLstatus(); // FIXME - why sending MIDI lightning if sample status is wrong?
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
* -------------------------------------------------------------------------- */
+#include <atomic>
#include <cassert>
#include "../glue/transport.h"
#include "../glue/main.h"
{
namespace
{
-bool running = false;
-float bpm = G_DEFAULT_BPM;
-int bars = G_DEFAULT_BARS;
-int beats = G_DEFAULT_BEATS;
-int quantize = G_DEFAULT_QUANTIZE;
-int quanto = 1; // quantizer step
-
-int framesInLoop = 0;
-int framesInBar = 0;
-int framesInBeat = 0;
-int framesInSeq = 0;
-int currentFrame = 0;
-int currentBeat = 0;
-
-int midiTCrate = 0; // send MTC data every midiTCrate frames
-int midiTCframes = 0;
-int midiTCseconds = 0;
-int midiTCminutes = 0;
-int midiTChours = 0;
+float bpm_ = G_DEFAULT_BPM;
+int bars_ = G_DEFAULT_BARS;
+int beats_ = G_DEFAULT_BEATS;
+int quanto_ = 1; // quantizer step
+std::atomic<int> quantize_(G_DEFAULT_QUANTIZE);
+std::atomic<ClockStatus> status_(ClockStatus::STOPPED);
+
+int framesInLoop_ = 0;
+int framesInBar_ = 0;
+int framesInBeat_ = 0;
+int framesInSeq_ = 0;
+std::atomic<int> currentFrameWait_(0); // Used only in wait mode
+std::atomic<int> currentFrame_(0);
+std::atomic<int> currentBeat_(0);
+
+int midiTCrate_ = 0; // Send MTC data every midiTCrate_ frames
+int midiTCframes_ = 0;
+int midiTCseconds_ = 0;
+int midiTCminutes_ = 0;
+int midiTChours_ = 0;
#ifdef G_OS_LINUX
-kernelAudio::JackState jackStatePrev;
+kernelAudio::JackState jackStatePrev_;
#endif
-void updateQuanto()
+void updateQuanto_()
{
- if (quantize != 0)
- quanto = framesInBeat / quantize;
+ if (quantize_.load() != 0)
+ quanto_ = framesInBeat_ / quantize_.load();
}
}; // {anonymous}
void init(int sampleRate, float midiTCfps)
{
- midiTCrate = (sampleRate / midiTCfps) * G_MAX_IO_CHANS; // stereo values
- running = false;
- bpm = G_DEFAULT_BPM;
- bars = G_DEFAULT_BARS;
- beats = G_DEFAULT_BEATS;
- quantize = G_DEFAULT_QUANTIZE;
+ status_.store(ClockStatus::STOPPED); // Must be the first thing to do
+ midiTCrate_ = (sampleRate / midiTCfps) * G_MAX_IO_CHANS; // stereo values
+ bpm_ = G_DEFAULT_BPM;
+ bars_ = G_DEFAULT_BARS;
+ beats_ = G_DEFAULT_BEATS;
+ quantize_.store(G_DEFAULT_QUANTIZE);
updateFrameBars();
}
bool isRunning()
{
- return running;
+ return status_.load() == ClockStatus::RUNNING;
}
-bool quantoHasPassed()
-{
- return currentFrame % (quanto) == 0;
-}
-
-
-bool isOnBar()
+bool isActive()
{
- /* A bar cannot occur at frame 0. That's the first beat. */
- return currentFrame % framesInBar == 0 && currentFrame != 0;
+ return status_.load() == ClockStatus::RUNNING || status_.load() == ClockStatus::WAITING;
}
-bool isOnBeat()
+bool quantoHasPassed()
{
- /* Skip frame 0: it is intended as 'first beat'. */
- /* TODO - this is wrong! */
- return currentFrame % framesInBeat == 0 && currentFrame > 0;
+ return currentFrame_.load() % (quanto_) == 0;
}
-bool isOnFirstBeat()
+bool isOnBar()
{
- return currentFrame == 0;
+ if (status_.load() == ClockStatus::WAITING)
+ return false;
+ return currentFrame_.load() % framesInBar_ == 0;
}
-void start()
+bool isOnBeat()
{
- running = true;
- if (conf::midiSync == MIDI_SYNC_CLOCK_M) {
- kernelMidi::send(MIDI_START, -1, -1);
- kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
- }
+ if (status_.load() == ClockStatus::WAITING)
+ return currentFrameWait_.load() % framesInBeat_ == 0;
+ return currentFrame_.load() % framesInBeat_ == 0;
}
-void stop()
+bool isOnFirstBeat()
{
- running = false;
- if (conf::midiSync == MIDI_SYNC_CLOCK_M)
- kernelMidi::send(MIDI_STOP, -1, -1);
+ return currentFrame_.load() == 0;
}
{
if (b < G_MIN_BPM)
b = G_MIN_BPM;
- bpm = b;
+ bpm_ = b;
updateFrameBars();
}
void setBars(int newBars)
{
- /* Bars cannot be greater than beats and must be a sub multiple of beats. If
+ /* Bars cannot be greater than beats_ and must be a sub multiple of beats_. If
not, approximate to the nearest (and greater) value available. */
- if (newBars > beats)
- bars = beats;
+ if (newBars > beats_)
+ bars_ = beats_;
else if (newBars <= 0)
- bars = 1;
- else if (beats % newBars != 0) {
- bars = newBars + (beats % newBars);
- if (beats % bars != 0) // it could be an odd value, let's check it (and avoid it)
- bars = bars - (beats % bars);
+ bars_ = 1;
+ else if (beats_ % newBars != 0) {
+ bars_ = newBars + (beats_ % newBars);
+ if (beats_ % bars_ != 0) // it could be an odd value, let's check it (and avoid it)
+ bars_ = bars_ - (beats_ % bars_);
}
else
- bars = newBars;
+ bars_ = newBars;
}
void setBeats(int b)
{
if (b > G_MAX_BEATS)
- beats = G_MAX_BEATS;
+ beats_ = G_MAX_BEATS;
else if (b < 1)
- beats = 1;
+ beats_ = 1;
else
- beats = b;
+ beats_ = b;
}
void setQuantize(int q)
{
- quantize = q;
- updateQuanto();
+ quantize_.store(q);
+ updateQuanto_();
+}
+
+
+void setStatus(ClockStatus s)
+{
+ status_.store(s);
+
+ if (s == ClockStatus::RUNNING) {
+ if (conf::midiSync == MIDI_SYNC_CLOCK_M) {
+ kernelMidi::send(MIDI_START, -1, -1);
+ kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
+ }
+ }
+ else
+ if (s == ClockStatus::STOPPED) {
+ if (conf::midiSync == MIDI_SYNC_CLOCK_M)
+ kernelMidi::send(MIDI_STOP, -1, -1);
+ }
}
/* -------------------------------------------------------------------------- */
-void incrCurrentFrame() {
- currentFrame++;
- if (currentFrame >= framesInLoop) {
- currentFrame = 0;
- currentBeat = 0;
+void incrCurrentFrame()
+{
+ if (status_.load() == ClockStatus::WAITING) {
+ currentFrameWait_++;
+ if (currentFrameWait_.load() >= framesInLoop_)
+ currentFrameWait_ = 0;
+ }
+ else {
+ currentFrame_++;
+ if (currentFrame_.load() >= framesInLoop_) {
+ currentFrame_.store(0);
+ currentBeat_.store(0);
+ }
+ else
+ if (isOnBeat())
+ currentBeat_++;
}
- else
- if (isOnBeat())
- currentBeat++;
}
void rewind()
{
- currentFrame = 0;
- currentBeat = 0;
+ currentFrameWait_.store(0);
+ currentFrame_.store(0);
+ currentBeat_.store(0);
sendMIDIrewind();
}
void updateFrameBars()
{
- /* framesInLoop ... loop length in frames, or samplerate * # frames per
- * current bpm * beats;
- * framesInBar .... n. of frames within a bar;
- * framesInBeat ... n. of frames within a beat;
- * framesInSeq .... number of frames in the whole sequencer. */
+ /* framesInLoop_ ... loop length in frames, or samplerate * # frames per
+ * current bpm_ * beats_;
+ * framesInBar_ .... n. of frames within a bar;
+ * framesInBeat_ ... n. of frames within a beat;
+ * framesInSeq_ .... number of frames in the whole sequencer. */
- framesInLoop = (conf::samplerate * (60.0f / bpm)) * beats;
- framesInBar = framesInLoop / bars;
- framesInBeat = framesInLoop / beats;
- framesInSeq = framesInBeat * G_MAX_BEATS;
+ framesInLoop_ = (conf::samplerate * (60.0f / bpm_)) * beats_;
+ framesInBar_ = framesInLoop_ / bars_;
+ framesInBeat_ = framesInLoop_ / beats_;
+ framesInSeq_ = framesInBeat_ * G_MAX_BEATS;
- updateQuanto();
+ updateQuanto_();
}
void sendMIDIsync()
{
+ /* Sending MIDI sync while waiting is meaningless. */
+
+ if (status_.load() == ClockStatus::WAITING)
+ return;
+
/* TODO - only Master (_M) is implemented so far. */
if (conf::midiSync == MIDI_SYNC_CLOCK_M) {
- if (currentFrame % (framesInBeat/24) == 0)
+ if (currentFrame_.load() % (framesInBeat_/24) == 0)
kernelMidi::send(MIDI_CLOCK, -1, -1);
return;
}
* 1-4 and 5-8. We check timecode frame's parity: if even, send
* range 1-4, if odd send 5-8. */
- if (currentFrame % midiTCrate != 0) // no timecode frame passed
+ if (currentFrame_.load() % midiTCrate_ != 0) // no timecode frame passed
return;
/* frame low nibble
* seconds low nibble
* seconds high nibble */
- if (midiTCframes % 2 == 0) {
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F) | 0x00, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4) | 0x10, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4) | 0x30, -1);
+ if (midiTCframes_ % 2 == 0) {
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ & 0x0F) | 0x00, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ >> 4) | 0x10, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds_ & 0x0F) | 0x20, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds_ >> 4) | 0x30, -1);
}
/* minutes low nibble
* hours high nibble SMPTE frame rate */
else {
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4) | 0x50, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F) | 0x60, -1);
- kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4) | 0x70, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes_ & 0x0F) | 0x40, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes_ >> 4) | 0x50, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ & 0x0F) | 0x60, -1);
+ kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ >> 4) | 0x70, -1);
}
- midiTCframes++;
+ midiTCframes_++;
/* check if total timecode frames are greater than timecode fps:
* if so, a second has passed */
- if (midiTCframes > conf::midiTCfps) {
- midiTCframes = 0;
- midiTCseconds++;
- if (midiTCseconds >= 60) {
- midiTCminutes++;
- midiTCseconds = 0;
- if (midiTCminutes >= 60) {
- midiTChours++;
- midiTCminutes = 0;
+ if (midiTCframes_ > conf::midiTCfps) {
+ midiTCframes_ = 0;
+ midiTCseconds_++;
+ if (midiTCseconds_ >= 60) {
+ midiTCminutes_++;
+ midiTCseconds_ = 0;
+ if (midiTCminutes_ >= 60) {
+ midiTChours_++;
+ midiTCminutes_ = 0;
}
}
- //gu_log("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes);
+ //gu_log("%d:%d:%d:%d\n", midiTChours_, midiTCminutes_, midiTCseconds_, midiTCframes_);
}
}
}
void sendMIDIrewind()
{
- midiTCframes = 0;
- midiTCseconds = 0;
- midiTCminutes = 0;
- midiTChours = 0;
+ midiTCframes_ = 0;
+ midiTCseconds_ = 0;
+ midiTCminutes_ = 0;
+ midiTChours_ = 0;
/* For cueing the slave to a particular start point, Quarter Frame
* messages are not used. Instead, an MTC Full Frame message should
{
kernelAudio::JackState jackState = kernelAudio::jackTransportQuery();
- if (jackState.running != jackStatePrev.running) {
+ if (jackState.running != jackStatePrev_.running) {
if (jackState.running) {
if (!isRunning())
c::transport::startSeq(false); // not from UI
c::transport::stopSeq(false); // not from UI
}
}
- if (jackState.bpm != jackStatePrev.bpm)
+ if (jackState.bpm != jackStatePrev_.bpm)
if (jackState.bpm > 1.0f) // 0 bpm if Jack does not send that info
- glue_setBpm(jackState.bpm);
+ c::main::setBpm(jackState.bpm);
- if (jackState.frame == 0 && jackState.frame != jackStatePrev.frame)
+ if (jackState.frame == 0 && jackState.frame != jackStatePrev_.frame)
c::transport::rewindSeq(false, false); // not from UI, don't notify jack (avoid loop)
- jackStatePrev = jackState;
+ jackStatePrev_ = jackState;
}
#endif
int getCurrentFrame()
{
- return currentFrame;
+ return currentFrame_.load();
}
int getFramesInLoop()
{
- return framesInLoop;
+ return framesInLoop_;
}
int getCurrentBeat()
{
- return currentBeat;
+ return currentBeat_.load();
}
int getQuantize()
{
- return quantize;
+ return quantize_.load();
}
float getBpm()
{
- return bpm;
+ return bpm_;
}
int getBeats()
{
- return beats;
+ return beats_;
}
int getBars()
{
- return bars;
+ return bars_;
}
int getQuanto()
{
- return quanto;
+ return quanto_;
}
int getFramesInBar()
{
- return framesInBar;
+ return framesInBar_;
}
int getFramesInBeat()
{
- return framesInBeat;
+ return framesInBeat_;
}
int getFramesInSeq()
{
- return framesInSeq;
+ return framesInSeq_;
}
+ClockStatus getStatus()
+{
+ return status_;
+}
+
}}}; // giada::m::clock::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define G_CLOCK_H
+#include "types.h"
+
+
namespace giada {
namespace m {
namespace clock
int getFramesInSeq();
int getQuantize();
int getQuanto();
+ClockStatus getStatus();
/* incrCurrentFrame
Increases current frame of a single step (+1). */
void setBeats(int b);
void setQuantize(int q);
+/* isRunning
+When clock is actually moving forward, i.e. ClockStatus == RUNNING. */
+
bool isRunning();
+
+/* isActive
+Clock is enabled, but might be in wait mode, i.e. ClockStatus == RUNNING or
+ClockStatus == WAITING. */
+
+bool isActive();
+
bool isOnBeat();
bool isOnBar();
bool isOnFirstBeat();
void rewind();
-void start();
-void stop();
+void setStatus(ClockStatus s);
}}}; // giada::m::clock::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../utils/log.h"
#include "storager.h"
#include "const.h"
+#include "types.h"
#include "conf.h"
if (channelsOut < 0) channelsOut = 0;
if (channelsIn < 0) channelsIn = 0;
if (buffersize < G_MIN_BUF_SIZE || buffersize > G_MAX_BUF_SIZE) buffersize = G_DEFAULT_BUFSIZE;
- if (delayComp < 0) delayComp = G_DEFAULT_DELAYCOMP;
if (midiPortOut < -1) midiPortOut = G_DEFAULT_MIDI_SYSTEM;
if (midiPortOut < -1) midiPortOut = G_DEFAULT_MIDI_PORT_OUT;
if (midiPortIn < -1) midiPortIn = G_DEFAULT_MIDI_PORT_IN;
if (sampleActionEditorH <= 0) sampleActionEditorH = 40;
if (velocityEditorH <= 0) velocityEditorH = 40;
if (envelopeEditorH <= 0) envelopeEditorH = 40;
- if (sampleEditorX < 0) sampleEditorX = 0;
+ if (sampleEditorX < 0) sampleEditorX = 0;
if (sampleEditorY < 0) sampleEditorY = 0;
if (sampleEditorW < 500) sampleEditorW = 500;
if (sampleEditorH < 292) sampleEditorH = 292;
if (sampleEditorGridVal < 0 || sampleEditorGridVal > G_MAX_GRID_VAL) sampleEditorGridVal = 0;
if (sampleEditorGridOn < 0) sampleEditorGridOn = 0;
- if (midiInputX < 0) midiInputX = 0;
- if (midiInputY < 0) midiInputY = 0;
- if (midiInputW < G_DEFAULT_MIDI_INPUT_UI_W) midiInputW = G_DEFAULT_MIDI_INPUT_UI_W;
- if (midiInputH < G_DEFAULT_MIDI_INPUT_UI_H) midiInputH = G_DEFAULT_MIDI_INPUT_UI_H;
+ if (midiInputX < 0) midiInputX = 0;
+ if (midiInputY < 0) midiInputY = 0;
+ if (midiInputW < G_DEFAULT_MIDI_INPUT_UI_W) midiInputW = G_DEFAULT_MIDI_INPUT_UI_W;
+ if (midiInputH < G_DEFAULT_MIDI_INPUT_UI_H) midiInputH = G_DEFAULT_MIDI_INPUT_UI_H;
if (configX < 0) configX = 0;
if (configY < 0) configY = 0;
if (pluginListX < 0) pluginListX = 0;
int channelsIn = 0;
int samplerate = G_DEFAULT_SAMPLERATE;
int buffersize = G_DEFAULT_BUFSIZE;
-int delayComp = G_DEFAULT_DELAYCOMP;
bool limitOutput = false;
int rsmpQuality = 0;
int nameX = 0;
int nameY = 0;
+int recTriggerMode = static_cast<int>(RecTriggerMode::NORMAL);
+float recTriggerLevel = G_DEFAULT_REC_TRIGGER_LEVEL;
+
#ifdef WITH_VST
int pluginChooserX = 0;
if (!storager::setInt(jRoot, CONF_KEY_CHANNELS_IN, channelsIn)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_SAMPLERATE, samplerate)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_BUFFER_SIZE, buffersize)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_DELAY_COMPENSATION, delayComp)) return 0;
if (!storager::setBool(jRoot, CONF_KEY_LIMIT_OUTPUT, limitOutput)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_RESAMPLE_QUALITY, rsmpQuality)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_MIDI_SYSTEM, midiSystem)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_BEATS_Y, beatsY)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_ABOUT_X, aboutX)) return 0;
if (!storager::setInt(jRoot, CONF_KEY_ABOUT_Y, aboutY)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_NAME_X, nameX)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_NAME_Y, nameY)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_X, midiInputX)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_Y, midiInputY)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_W, midiInputW)) return 0;
- if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_H, midiInputH)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_NAME_X, nameX)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_NAME_Y, nameY)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_X, midiInputX)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_Y, midiInputY)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_W, midiInputW)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_MIDI_INPUT_H, midiInputH)) return 0;
+ if (!storager::setInt(jRoot, CONF_KEY_REC_TRIGGER_MODE, recTriggerMode)) return 0;
+ if (!storager::setFloat(jRoot, CONF_KEY_REC_TRIGGER_LEVEL, recTriggerLevel)) return 0;
#ifdef WITH_VST
json_object_set_new(jRoot, CONF_KEY_CHANNELS_IN, json_integer(channelsIn));
json_object_set_new(jRoot, CONF_KEY_SAMPLERATE, json_integer(samplerate));
json_object_set_new(jRoot, CONF_KEY_BUFFER_SIZE, json_integer(buffersize));
- json_object_set_new(jRoot, CONF_KEY_DELAY_COMPENSATION, json_integer(delayComp));
json_object_set_new(jRoot, CONF_KEY_LIMIT_OUTPUT, json_boolean(limitOutput));
json_object_set_new(jRoot, CONF_KEY_RESAMPLE_QUALITY, json_integer(rsmpQuality));
json_object_set_new(jRoot, CONF_KEY_MIDI_SYSTEM, json_integer(midiSystem));
json_object_set_new(jRoot, CONF_KEY_MIDI_IN_FILTER, json_integer(midiInFilter));
json_object_set_new(jRoot, CONF_KEY_MIDI_IN_REWIND, json_integer(midiInRewind));
json_object_set_new(jRoot, CONF_KEY_MIDI_IN_START_STOP, json_integer(midiInStartStop));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_ACTION_REC, json_integer(midiInActionRec));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_INPUT_REC, json_integer(midiInInputRec));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_METRONOME, json_integer(midiInMetronome));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_IN, json_integer(midiInVolumeIn));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_OUT, json_integer(midiInVolumeOut));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_DOUBLE, json_integer(midiInBeatDouble));
- json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_HALF, json_integer(midiInBeatHalf));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_ACTION_REC, json_integer(midiInActionRec));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_INPUT_REC, json_integer(midiInInputRec));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_METRONOME, json_integer(midiInMetronome));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_IN, json_integer(midiInVolumeIn));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_OUT, json_integer(midiInVolumeOut));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_DOUBLE, json_integer(midiInBeatDouble));
+ json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_HALF, json_integer(midiInBeatHalf));
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_MIDI_INPUT_Y, json_integer(midiInputY));
json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_W, json_integer(midiInputW));
json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_H, json_integer(midiInputH));
+ json_object_set_new(jRoot, CONF_KEY_REC_TRIGGER_MODE, json_integer(recTriggerMode));
+ json_object_set_new(jRoot, CONF_KEY_REC_TRIGGER_LEVEL, json_real(recTriggerLevel));
#ifdef WITH_VST
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
extern int channelsIn;
extern int samplerate;
extern int buffersize;
-extern int delayComp;
extern bool limitOutput;
extern int rsmpQuality;
extern int aboutX, aboutY;
extern int nameX, nameY;
+extern int recTriggerMode;
+extern float recTriggerLevel;
+
#ifdef WITH_VST
extern int pluginChooserX, pluginChooserY, pluginChooserW, pluginChooserH;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
/* -- version --------------------------------------------------------------- */
-#define G_APP_NAME "Giada"
-#define G_VERSION_STR "0.15.3"
-#define G_VERSION_MAJOR 0
-#define G_VERSION_MINOR 15
-#define G_VERSION_PATCH 3
+constexpr auto G_APP_NAME = "Giada";
+constexpr auto G_VERSION_STR = "0.15.4";
+constexpr int G_VERSION_MAJOR = 0;
+constexpr int G_VERSION_MINOR = 15;
+constexpr int G_VERSION_PATCH = 4;
-#define CONF_FILENAME "giada.conf"
+constexpr auto CONF_FILENAME = "giada.conf";
#ifdef G_OS_WINDOWS
#define G_SLASH '\\'
/* -- 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_PULSE 0x20 // 0010 0000
-#define G_SYS_API_WASAPI 0x40 // 0100 0000
-#define G_SYS_API_ANY 0x7F // 0111 1111
+constexpr int G_SYS_API_NONE = 0x00; // 0000 0000
+constexpr int G_SYS_API_JACK = 0x01; // 0000 0001
+constexpr int G_SYS_API_ALSA = 0x02; // 0000 0010
+constexpr int G_SYS_API_DS = 0x04; // 0000 0100
+constexpr int G_SYS_API_ASIO = 0x08; // 0000 1000
+constexpr int G_SYS_API_CORE = 0x10; // 0001 0000
+constexpr int G_SYS_API_PULSE = 0x20; // 0010 0000
+constexpr int G_SYS_API_WASAPI = 0x40; // 0100 0000
+constexpr int 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
+constexpr int G_MIDI_API_JACK = 0x01; // 0000 0001
+constexpr int G_MIDI_API_ALSA = 0x02; // 0000 0010
#define G_DEFAULT_SOUNDSYS G_SYS_API_CORE
#endif
-#define G_DEFAULT_SOUNDDEV_OUT 0 // FIXME - please override with rtAudio::getDefaultDevice (or similar)
-#define G_DEFAULT_SOUNDDEV_IN -1 // no recording by default: input disabled
-#define G_DEFAULT_MIDI_SYSTEM 0
-#define G_DEFAULT_MIDI_PORT_IN -1
-#define G_DEFAULT_MIDI_PORT_OUT -1
-#define G_DEFAULT_SAMPLERATE 44100
-#define G_DEFAULT_BUFSIZE 1024
-#define G_DEFAULT_DELAYCOMP 0
-#define G_DEFAULT_BIT_DEPTH 32 // float
-#define G_DEFAULT_VOL 1.0f
-#define G_DEFAULT_PITCH 1.0f
-#define G_DEFAULT_BOOST 1.0f
-#define G_DEFAULT_OUT_VOL 1.0f
-#define G_DEFAULT_IN_VOL 1.0f
-#define G_DEFAULT_BPM 120.0f
-#define G_DEFAULT_BEATS 4
-#define G_DEFAULT_BARS 1
-#define G_DEFAULT_QUANTIZE 0 // quantizer off
-#define G_DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed
-#define G_DEFAULT_COLUMN_WIDTH 380
-#define G_DEFAULT_PATCH_NAME "(default patch)"
-#define G_DEFAULT_MIDI_INPUT_UI_W 300
-#define G_DEFAULT_MIDI_INPUT_UI_H 350
-#define G_DEFAULT_ACTION_SIZE 8192 // frames
-#define G_DEFAULT_ZOOM_RATIO 128
-
-
-
-/* -- actions --------------------------------------------------------------- */
-#define G_ACTION_KEYPRESS 0x01 // 0000 0001
-#define G_ACTION_KEYREL 0x02 // 0000 0010
-#define G_ACTION_KILL 0x04 // 0000 0100
-#define G_ACTION_VOLUME 0x20 // 0010 0000
-#define G_ACTION_MIDI 0x40 // 0100 0000
-
-#define G_ACTION_KEYS 0x03 // 0000 0011 any key
-
-#define G_RANGE_CHAR 0x01 // range for MIDI (0-127)
-#define G_RANGE_FLOAT 0x02 // range for volumes and VST params (0.0-1.0)
+constexpr int G_DEFAULT_SOUNDDEV_OUT = 0; // FIXME - please override with rtAudio::getDefaultDevice (or similar)
+constexpr int G_DEFAULT_SOUNDDEV_IN = -1; // no recording by default: input disabled
+constexpr int G_DEFAULT_MIDI_SYSTEM = 0;
+constexpr int G_DEFAULT_MIDI_PORT_IN = -1;
+constexpr int G_DEFAULT_MIDI_PORT_OUT = -1;
+constexpr int G_DEFAULT_SAMPLERATE = 44100;
+constexpr int G_DEFAULT_BUFSIZE = 1024;
+constexpr int G_DEFAULT_BIT_DEPTH = 32; // float
+constexpr float G_DEFAULT_VOL = 1.0f;
+constexpr float G_DEFAULT_PITCH = 1.0f;
+constexpr float G_DEFAULT_BOOST = 1.0f;
+constexpr float G_DEFAULT_OUT_VOL = 1.0f;
+constexpr float G_DEFAULT_IN_VOL = 1.0f;
+constexpr float G_DEFAULT_BPM = 120.0f;
+constexpr int G_DEFAULT_BEATS = 4;
+constexpr int G_DEFAULT_BARS = 1;
+constexpr int G_DEFAULT_QUANTIZE = 0; // quantizer off
+constexpr float G_DEFAULT_FADEOUT_STEP = 0.01f; // micro-fadeout speed
+constexpr int G_DEFAULT_COLUMN_WIDTH = 380;
+constexpr auto G_DEFAULT_PATCH_NAME = "(default patch)";
+constexpr int G_DEFAULT_MIDI_INPUT_UI_W = 300;
+constexpr int G_DEFAULT_MIDI_INPUT_UI_H = 350;
+constexpr int G_DEFAULT_ACTION_SIZE = 8192; // frames
+constexpr int G_DEFAULT_ZOOM_RATIO = 128;
+constexpr float G_DEFAULT_REC_TRIGGER_LEVEL = -10.0f;
/* -- MIDI signals -------------------------------------------------------------
-All signals are set to channel 0 (where channels are considered). It's up to the
-caller to bitmask them with the proper channel number.
Channel voices messages - controller (0xB0) is a special subset of this family:
it drives knobs, volume, faders and such. */
#define MIDI_CONTROLLER 0xB0 << 24
-#define MIDI_NOTE_ON 0x90 << 24
-#define MIDI_NOTE_OFF 0x80 << 24
-#define MIDI_VELOCITY 0x3F << 8
#define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16)
-#define MIDI_VOLUME (MIDI_CONTROLLER) | (0x07 << 16)
/* system common / real-time messages. Single bytes */
/* JSON patch keys */
-#define PATCH_KEY_HEADER "header"
-#define PATCH_KEY_VERSION "version"
-#define PATCH_KEY_VERSION_MAJOR "version_major"
-#define PATCH_KEY_VERSION_MINOR "version_minor"
-#define PATCH_KEY_VERSION_PATCH "version_patch"
-#define PATCH_KEY_NAME "name"
-#define PATCH_KEY_BPM "bpm"
-#define PATCH_KEY_BARS "bars"
-#define PATCH_KEY_BEATS "beats"
-#define PATCH_KEY_QUANTIZE "quantize"
-#define PATCH_KEY_MASTER_VOL_IN "master_vol_in"
-#define PATCH_KEY_MASTER_VOL_OUT "master_vol_out"
-#define PATCH_KEY_METRONOME "metronome"
-#define PATCH_KEY_LAST_TAKE_ID "last_take_id"
-#define PATCH_KEY_SAMPLERATE "samplerate"
-#define PATCH_KEY_COLUMNS "columns"
-#define PATCH_KEY_MASTER_OUT_PLUGINS "master_out_plugins"
-#define PATCH_KEY_MASTER_IN_PLUGINS "master_in_plugins"
-#define PATCH_KEY_CHANNELS "channels"
-#define PATCH_KEY_CHANNEL_TYPE "type"
-#define PATCH_KEY_CHANNEL_INDEX "index"
-#define PATCH_KEY_CHANNEL_SIZE "size"
-#define PATCH_KEY_CHANNEL_NAME "name"
-#define PATCH_KEY_CHANNEL_COLUMN "column"
-#define PATCH_KEY_CHANNEL_MUTE "mute"
-#define PATCH_KEY_CHANNEL_SOLO "solo"
-#define PATCH_KEY_CHANNEL_VOLUME "volume"
-#define PATCH_KEY_CHANNEL_PAN "pan"
-#define PATCH_KEY_CHANNEL_MIDI_IN "midi_in"
-#define PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL "midi_in_velo_as_vol"
-#define PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS "midi_in_keypress"
-#define PATCH_KEY_CHANNEL_MIDI_IN_KEYREL "midi_in_keyrel"
-#define PATCH_KEY_CHANNEL_MIDI_IN_KILL "midi_in_kill"
-#define PATCH_KEY_CHANNEL_MIDI_IN_ARM "midi_in_arm"
-#define PATCH_KEY_CHANNEL_MIDI_IN_VOLUME "midi_in_volume"
-#define PATCH_KEY_CHANNEL_MIDI_IN_MUTE "midi_in_mute"
-#define PATCH_KEY_CHANNEL_MIDI_IN_FILTER "midi_in_filter"
-#define PATCH_KEY_CHANNEL_MIDI_IN_SOLO "midi_in_solo"
-#define PATCH_KEY_CHANNEL_MIDI_OUT_L "midi_out_l"
-#define PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING "midi_out_l_playing"
-#define PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE "midi_out_l_mute"
-#define PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO "midi_out_l_solo"
-#define PATCH_KEY_CHANNEL_SAMPLE_PATH "sample_path"
-#define PATCH_KEY_CHANNEL_KEY "key"
-#define PATCH_KEY_CHANNEL_MODE "mode"
-#define PATCH_KEY_CHANNEL_BEGIN "begin"
-#define PATCH_KEY_CHANNEL_END "end"
-#define PATCH_KEY_CHANNEL_BOOST "boost"
-#define PATCH_KEY_CHANNEL_REC_ACTIVE "rec_active"
-#define PATCH_KEY_CHANNEL_PITCH "pitch"
-#define PATCH_KEY_CHANNEL_INPUT_MONITOR "input_monitor"
-#define PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS "midi_in_read_actions"
-#define PATCH_KEY_CHANNEL_MIDI_IN_PITCH "midi_in_pitch"
-#define PATCH_KEY_CHANNEL_MIDI_OUT "midi_out"
-#define PATCH_KEY_CHANNEL_MIDI_OUT_CHAN "midi_out_chan"
-#define PATCH_KEY_CHANNEL_PLUGINS "plugins"
-#define PATCH_KEY_CHANNEL_ACTIONS "actions"
-#define PATCH_KEY_CHANNEL_ARMED "armed"
-#define PATCH_KEY_ACTION_TYPE "type"
-#define PATCH_KEY_ACTION_FRAME "frame"
-#define PATCH_KEY_ACTION_F_VALUE "f_value"
-#define PATCH_KEY_ACTION_I_VALUE "i_value"
-#define PATCH_KEY_PLUGIN_PATH "path"
-#define PATCH_KEY_PLUGIN_BYPASS "bypass"
-#define PATCH_KEY_PLUGIN_PARAMS "params"
-#define PATCH_KEY_PLUGIN_MIDI_IN_PARAMS "midi_in_params"
-#define PATCH_KEY_COLUMN_INDEX "index"
-#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"
+constexpr auto PATCH_KEY_HEADER = "header";
+constexpr auto PATCH_KEY_VERSION = "version";
+constexpr auto PATCH_KEY_VERSION_MAJOR = "version_major";
+constexpr auto PATCH_KEY_VERSION_MINOR = "version_minor";
+constexpr auto PATCH_KEY_VERSION_PATCH = "version_patch";
+constexpr auto PATCH_KEY_NAME = "name";
+constexpr auto PATCH_KEY_BPM = "bpm";
+constexpr auto PATCH_KEY_BARS = "bars";
+constexpr auto PATCH_KEY_BEATS = "beats";
+constexpr auto PATCH_KEY_QUANTIZE = "quantize";
+constexpr auto PATCH_KEY_MASTER_VOL_IN = "master_vol_in";
+constexpr auto PATCH_KEY_MASTER_VOL_OUT = "master_vol_out";
+constexpr auto PATCH_KEY_METRONOME = "metronome";
+constexpr auto PATCH_KEY_LAST_TAKE_ID = "last_take_id";
+constexpr auto PATCH_KEY_SAMPLERATE = "samplerate";
+constexpr auto PATCH_KEY_COLUMNS = "columns";
+constexpr auto PATCH_KEY_MASTER_OUT_PLUGINS = "master_out_plugins";
+constexpr auto PATCH_KEY_MASTER_IN_PLUGINS = "master_in_plugins";
+constexpr auto PATCH_KEY_CHANNELS = "channels";
+constexpr auto PATCH_KEY_CHANNEL_TYPE = "type";
+constexpr auto PATCH_KEY_CHANNEL_INDEX = "index";
+constexpr auto PATCH_KEY_CHANNEL_SIZE = "size";
+constexpr auto PATCH_KEY_CHANNEL_NAME = "name";
+constexpr auto PATCH_KEY_CHANNEL_COLUMN = "column";
+constexpr auto PATCH_KEY_CHANNEL_MUTE = "mute";
+constexpr auto PATCH_KEY_CHANNEL_SOLO = "solo";
+constexpr auto PATCH_KEY_CHANNEL_VOLUME = "volume";
+constexpr auto PATCH_KEY_CHANNEL_PAN = "pan";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN = "midi_in";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_VELO_AS_VOL = "midi_in_velo_as_vol";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS = "midi_in_keypress";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_KEYREL = "midi_in_keyrel";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_KILL = "midi_in_kill";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_ARM = "midi_in_arm";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_VOLUME = "midi_in_volume";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_MUTE = "midi_in_mute";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_FILTER = "midi_in_filter";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_SOLO = "midi_in_solo";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT_L = "midi_out_l";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING = "midi_out_l_playing";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE = "midi_out_l_mute";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO = "midi_out_l_solo";
+constexpr auto PATCH_KEY_CHANNEL_SAMPLE_PATH = "sample_path";
+constexpr auto PATCH_KEY_CHANNEL_KEY = "key";
+constexpr auto PATCH_KEY_CHANNEL_MODE = "mode";
+constexpr auto PATCH_KEY_CHANNEL_BEGIN = "begin";
+constexpr auto PATCH_KEY_CHANNEL_END = "end";
+constexpr auto PATCH_KEY_CHANNEL_BOOST = "boost";
+constexpr auto PATCH_KEY_CHANNEL_READ_ACTIONS = "rec_active"; // TODO update string key in 1.0
+constexpr auto PATCH_KEY_CHANNEL_PITCH = "pitch";
+constexpr auto PATCH_KEY_CHANNEL_INPUT_MONITOR = "input_monitor";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS = "midi_in_read_actions";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_IN_PITCH = "midi_in_pitch";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT = "midi_out";
+constexpr auto PATCH_KEY_CHANNEL_MIDI_OUT_CHAN = "midi_out_chan";
+constexpr auto PATCH_KEY_CHANNEL_PLUGINS = "plugins";
+constexpr auto PATCH_KEY_CHANNEL_ACTIONS = "actions";
+constexpr auto PATCH_KEY_CHANNEL_ARMED = "armed";
+constexpr auto PATCH_KEY_ACTION_TYPE = "type";
+constexpr auto PATCH_KEY_ACTION_FRAME = "frame";
+constexpr auto PATCH_KEY_ACTION_F_VALUE = "f_value";
+constexpr auto PATCH_KEY_ACTION_I_VALUE = "i_value";
+constexpr auto PATCH_KEY_PLUGIN_PATH = "path";
+constexpr auto PATCH_KEY_PLUGIN_BYPASS = "bypass";
+constexpr auto PATCH_KEY_PLUGIN_PARAMS = "params";
+constexpr auto PATCH_KEY_PLUGIN_MIDI_IN_PARAMS = "midi_in_params";
+constexpr auto PATCH_KEY_COLUMN_INDEX = "index";
+constexpr auto PATCH_KEY_COLUMN_WIDTH = "width";
+constexpr auto PATCH_KEY_COLUMN_CHANNELS = "channels";
+constexpr auto G_PATCH_KEY_ACTION_ID = "id";
+constexpr auto G_PATCH_KEY_ACTION_CHANNEL = "channel";
+constexpr auto G_PATCH_KEY_ACTION_FRAME = "frame";
+constexpr auto G_PATCH_KEY_ACTION_EVENT = "event";
+constexpr auto G_PATCH_KEY_ACTION_PREV = "prev";
+constexpr auto G_PATCH_KEY_ACTION_NEXT = "next";
/* JSON config keys */
-#define CONF_KEY_HEADER "header"
-#define CONF_KEY_LOG_MODE "log_mode"
-#define CONF_KEY_SOUND_SYSTEM "sound_system"
-#define CONF_KEY_SOUND_DEVICE_IN "sound_device_in"
-#define CONF_KEY_SOUND_DEVICE_OUT "sound_device_out"
-#define CONF_KEY_CHANNELS_IN "channels_in"
-#define CONF_KEY_CHANNELS_OUT "channels_out"
-#define CONF_KEY_SAMPLERATE "samplerate"
-#define CONF_KEY_BUFFER_SIZE "buffer_size"
-#define CONF_KEY_DELAY_COMPENSATION "delay_compensation"
-#define CONF_KEY_LIMIT_OUTPUT "limit_output"
-#define CONF_KEY_RESAMPLE_QUALITY "resample_quality"
-#define CONF_KEY_MIDI_SYSTEM "midi_system"
-#define CONF_KEY_MIDI_PORT_OUT "midi_port_out"
-#define CONF_KEY_MIDI_PORT_IN "midi_port_in"
-#define CONF_KEY_MIDIMAP_PATH "midimap_path"
-#define CONF_KEY_LAST_MIDIMAP "last_midimap"
-#define CONF_KEY_MIDI_SYNC "midi_sync"
-#define CONF_KEY_MIDI_TC_FPS "midi_tc_fps"
-#define CONF_KEY_MIDI_IN "midi_in"
-#define CONF_KEY_MIDI_IN_FILTER "midi_in_filter"
-#define CONF_KEY_MIDI_IN_REWIND "midi_in_rewind"
-#define CONF_KEY_MIDI_IN_START_STOP "midi_in_start_stop"
-#define CONF_KEY_MIDI_IN_ACTION_REC "midi_in_action_rec"
-#define CONF_KEY_MIDI_IN_INPUT_REC "midi_in_input_rec"
-#define CONF_KEY_MIDI_IN_METRONOME "midi_in_metronome"
-#define CONF_KEY_MIDI_IN_VOLUME_IN "midi_in_volume_in"
-#define CONF_KEY_MIDI_IN_VOLUME_OUT "midi_in_volume_out"
-#define CONF_KEY_MIDI_IN_BEAT_DOUBLE "midi_in_beat_doble"
-#define CONF_KEY_MIDI_IN_BEAT_HALF "midi_in_beat_half"
-#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_INPUT_MONITOR_DEFAULT_ON "input_monitor_default_on"
-#define CONF_KEY_PLUGINS_PATH "plugins_path"
-#define CONF_KEY_PATCHES_PATH "patches_path"
-#define CONF_KEY_SAMPLES_PATH "samples_path"
-#define CONF_KEY_MAIN_WINDOW_X "main_window_x"
-#define CONF_KEY_MAIN_WINDOW_Y "main_window_y"
-#define CONF_KEY_MAIN_WINDOW_W "main_window_w"
-#define CONF_KEY_MAIN_WINDOW_H "main_window_h"
-#define CONF_KEY_BROWSER_X "browser_x"
-#define CONF_KEY_BROWSER_Y "browser_y"
-#define CONF_KEY_BROWSER_W "browser_w"
-#define CONF_KEY_BROWSER_H "browser_h"
-#define CONF_KEY_BROWSER_POSITION "browser_position"
-#define CONF_KEY_BROWSER_LAST_PATH "browser_last_path"
-#define CONF_KEY_BROWSER_LAST_VALUE "browser_last_value"
-#define CONF_KEY_ACTION_EDITOR_X "action_editor_x"
-#define CONF_KEY_ACTION_EDITOR_Y "action_editor_y"
-#define CONF_KEY_ACTION_EDITOR_W "action_editor_w"
-#define CONF_KEY_ACTION_EDITOR_H "action_editor_h"
-#define CONF_KEY_ACTION_EDITOR_ZOOM "action_editor_zoom"
-#define CONF_KEY_ACTION_EDITOR_GRID_VAL "action_editor_grid_val"
-#define CONF_KEY_ACTION_EDITOR_GRID_ON "action_editor_grid_on"
-#define CONF_KEY_SAMPLE_EDITOR_X "sample_editor_x"
-#define CONF_KEY_SAMPLE_EDITOR_Y "sample_editor_y"
-#define CONF_KEY_SAMPLE_EDITOR_W "sample_editor_w"
-#define CONF_KEY_SAMPLE_EDITOR_H "sample_editor_h"
-#define CONF_KEY_SAMPLE_EDITOR_GRID_VAL "sample_editor_grid_val"
-#define CONF_KEY_SAMPLE_EDITOR_GRID_ON "sample_editor_grid_on"
-#define CONF_KEY_PIANO_ROLL_Y "piano_roll_y"
-#define CONF_KEY_PIANO_ROLL_H "piano_roll_h"
-#define CONF_KEY_SAMPLE_ACTION_EDITOR_H "sample_action_editor_h"
-#define CONF_KEY_VELOCITY_EDITOR_H "velocity_editor_h"
-#define CONF_KEY_ENVELOPE_EDITOR_H "envelope_editor_h"
-#define CONF_KEY_PLUGIN_LIST_X "plugin_list_x"
-#define CONF_KEY_PLUGIN_LIST_Y "plugin_list_y"
-#define CONF_KEY_CONFIG_X "config_x"
-#define CONF_KEY_CONFIG_Y "config_y"
-#define CONF_KEY_BPM_X "bpm_x"
-#define CONF_KEY_BPM_Y "bpm_y"
-#define CONF_KEY_BEATS_X "beats_x"
-#define CONF_KEY_BEATS_Y "beats_y"
-#define CONF_KEY_ABOUT_X "about_x"
-#define CONF_KEY_ABOUT_Y "about_y"
-#define CONF_KEY_NAME_X "name_x"
-#define CONF_KEY_NAME_Y "name_y"
-#define CONF_KEY_PLUGIN_CHOOSER_X "plugin_chooser_x"
-#define CONF_KEY_PLUGIN_CHOOSER_Y "plugin_chooser_y"
-#define CONF_KEY_PLUGIN_CHOOSER_W "plugin_chooser_w"
-#define CONF_KEY_PLUGIN_CHOOSER_H "plugin_chooser_h"
-#define CONF_KEY_MIDI_INPUT_X "midi_input_x"
-#define CONF_KEY_MIDI_INPUT_Y "midi_input_y"
-#define CONF_KEY_MIDI_INPUT_W "midi_input_w"
-#define CONF_KEY_MIDI_INPUT_H "midi_input_h"
-#define CONF_KEY_PLUGIN_SORT_METHOD "plugin_sort_method"
+constexpr auto CONF_KEY_HEADER = "header";
+constexpr auto CONF_KEY_LOG_MODE = "log_mode";
+constexpr auto CONF_KEY_SOUND_SYSTEM = "sound_system";
+constexpr auto CONF_KEY_SOUND_DEVICE_IN = "sound_device_in";
+constexpr auto CONF_KEY_SOUND_DEVICE_OUT = "sound_device_out";
+constexpr auto CONF_KEY_CHANNELS_IN = "channels_in";
+constexpr auto CONF_KEY_CHANNELS_OUT = "channels_out";
+constexpr auto CONF_KEY_SAMPLERATE = "samplerate";
+constexpr auto CONF_KEY_BUFFER_SIZE = "buffer_size";
+constexpr auto CONF_KEY_DELAY_COMPENSATION = "delay_compensation";
+constexpr auto CONF_KEY_LIMIT_OUTPUT = "limit_output";
+constexpr auto CONF_KEY_RESAMPLE_QUALITY = "resample_quality";
+constexpr auto CONF_KEY_MIDI_SYSTEM = "midi_system";
+constexpr auto CONF_KEY_MIDI_PORT_OUT = "midi_port_out";
+constexpr auto CONF_KEY_MIDI_PORT_IN = "midi_port_in";
+constexpr auto CONF_KEY_MIDIMAP_PATH = "midimap_path";
+constexpr auto CONF_KEY_LAST_MIDIMAP = "last_midimap";
+constexpr auto CONF_KEY_MIDI_SYNC = "midi_sync";
+constexpr auto CONF_KEY_MIDI_TC_FPS = "midi_tc_fps";
+constexpr auto CONF_KEY_MIDI_IN = "midi_in";
+constexpr auto CONF_KEY_MIDI_IN_FILTER = "midi_in_filter";
+constexpr auto CONF_KEY_MIDI_IN_REWIND = "midi_in_rewind";
+constexpr auto CONF_KEY_MIDI_IN_START_STOP = "midi_in_start_stop";
+constexpr auto CONF_KEY_MIDI_IN_ACTION_REC = "midi_in_action_rec";
+constexpr auto CONF_KEY_MIDI_IN_INPUT_REC = "midi_in_input_rec";
+constexpr auto CONF_KEY_MIDI_IN_METRONOME = "midi_in_metronome";
+constexpr auto CONF_KEY_MIDI_IN_VOLUME_IN = "midi_in_volume_in";
+constexpr auto CONF_KEY_MIDI_IN_VOLUME_OUT = "midi_in_volume_out";
+constexpr auto CONF_KEY_MIDI_IN_BEAT_DOUBLE = "midi_in_beat_doble";
+constexpr auto CONF_KEY_MIDI_IN_BEAT_HALF = "midi_in_beat_half";
+constexpr auto CONF_KEY_RECS_STOP_ON_CHAN_HALT = "recs_stop_on_chan_halt";
+constexpr auto CONF_KEY_CHANS_STOP_ON_SEQ_HALT = "chans_stop_on_seq_halt";
+constexpr auto CONF_KEY_TREAT_RECS_AS_LOOPS = "treat_recs_as_loops";
+constexpr auto CONF_KEY_INPUT_MONITOR_DEFAULT_ON = "input_monitor_default_on";
+constexpr auto CONF_KEY_PLUGINS_PATH = "plugins_path";
+constexpr auto CONF_KEY_PATCHES_PATH = "patches_path";
+constexpr auto CONF_KEY_SAMPLES_PATH = "samples_path";
+constexpr auto CONF_KEY_MAIN_WINDOW_X = "main_window_x";
+constexpr auto CONF_KEY_MAIN_WINDOW_Y = "main_window_y";
+constexpr auto CONF_KEY_MAIN_WINDOW_W = "main_window_w";
+constexpr auto CONF_KEY_MAIN_WINDOW_H = "main_window_h";
+constexpr auto CONF_KEY_BROWSER_X = "browser_x";
+constexpr auto CONF_KEY_BROWSER_Y = "browser_y";
+constexpr auto CONF_KEY_BROWSER_W = "browser_w";
+constexpr auto CONF_KEY_BROWSER_H = "browser_h";
+constexpr auto CONF_KEY_BROWSER_POSITION = "browser_position";
+constexpr auto CONF_KEY_BROWSER_LAST_PATH = "browser_last_path";
+constexpr auto CONF_KEY_BROWSER_LAST_VALUE = "browser_last_value";
+constexpr auto CONF_KEY_ACTION_EDITOR_X = "action_editor_x";
+constexpr auto CONF_KEY_ACTION_EDITOR_Y = "action_editor_y";
+constexpr auto CONF_KEY_ACTION_EDITOR_W = "action_editor_w";
+constexpr auto CONF_KEY_ACTION_EDITOR_H = "action_editor_h";
+constexpr auto CONF_KEY_ACTION_EDITOR_ZOOM = "action_editor_zoom";
+constexpr auto CONF_KEY_ACTION_EDITOR_GRID_VAL = "action_editor_grid_val";
+constexpr auto CONF_KEY_ACTION_EDITOR_GRID_ON = "action_editor_grid_on";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_X = "sample_editor_x";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_Y = "sample_editor_y";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_W = "sample_editor_w";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_H = "sample_editor_h";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_GRID_VAL = "sample_editor_grid_val";
+constexpr auto CONF_KEY_SAMPLE_EDITOR_GRID_ON = "sample_editor_grid_on";
+constexpr auto CONF_KEY_PIANO_ROLL_Y = "piano_roll_y";
+constexpr auto CONF_KEY_PIANO_ROLL_H = "piano_roll_h";
+constexpr auto CONF_KEY_SAMPLE_ACTION_EDITOR_H = "sample_action_editor_h";
+constexpr auto CONF_KEY_VELOCITY_EDITOR_H = "velocity_editor_h";
+constexpr auto CONF_KEY_ENVELOPE_EDITOR_H = "envelope_editor_h";
+constexpr auto CONF_KEY_PLUGIN_LIST_X = "plugin_list_x";
+constexpr auto CONF_KEY_PLUGIN_LIST_Y = "plugin_list_y";
+constexpr auto CONF_KEY_CONFIG_X = "config_x";
+constexpr auto CONF_KEY_CONFIG_Y = "config_y";
+constexpr auto CONF_KEY_BPM_X = "bpm_x";
+constexpr auto CONF_KEY_BPM_Y = "bpm_y";
+constexpr auto CONF_KEY_BEATS_X = "beats_x";
+constexpr auto CONF_KEY_BEATS_Y = "beats_y";
+constexpr auto CONF_KEY_ABOUT_X = "about_x";
+constexpr auto CONF_KEY_ABOUT_Y = "about_y";
+constexpr auto CONF_KEY_NAME_X = "name_x";
+constexpr auto CONF_KEY_NAME_Y = "name_y";
+constexpr auto CONF_KEY_PLUGIN_CHOOSER_X = "plugin_chooser_x";
+constexpr auto CONF_KEY_PLUGIN_CHOOSER_Y = "plugin_chooser_y";
+constexpr auto CONF_KEY_PLUGIN_CHOOSER_W = "plugin_chooser_w";
+constexpr auto CONF_KEY_PLUGIN_CHOOSER_H = "plugin_chooser_h";
+constexpr auto CONF_KEY_MIDI_INPUT_X = "midi_input_x";
+constexpr auto CONF_KEY_MIDI_INPUT_Y = "midi_input_y";
+constexpr auto CONF_KEY_MIDI_INPUT_W = "midi_input_w";
+constexpr auto CONF_KEY_MIDI_INPUT_H = "midi_input_h";
+constexpr auto CONF_KEY_PLUGIN_SORT_METHOD = "plugin_sort_method";
+constexpr auto CONF_KEY_REC_TRIGGER_MODE = "rec_trigger_mode";
+constexpr auto CONF_KEY_REC_TRIGGER_LEVEL = "rec_trigger_level";
/* 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_PLAYING_INAUDIBLE "playing_inaudible"
-#define MIDIMAP_KEY_STOPPING "stopping"
-#define MIDIMAP_KEY_STOPPED "stopped"
-#define MIDIMAP_KEY_CHANNEL "channel"
-#define MIDIMAP_KEY_MESSAGE "message"
+constexpr auto MIDIMAP_KEY_BRAND = "brand";
+constexpr auto MIDIMAP_KEY_DEVICE = "device";
+constexpr auto MIDIMAP_KEY_INIT_COMMANDS = "init_commands";
+constexpr auto MIDIMAP_KEY_MUTE_ON = "mute_on";
+constexpr auto MIDIMAP_KEY_MUTE_OFF = "mute_off";
+constexpr auto MIDIMAP_KEY_SOLO_ON = "solo_on";
+constexpr auto MIDIMAP_KEY_SOLO_OFF = "solo_off";
+constexpr auto MIDIMAP_KEY_WAITING = "waiting";
+constexpr auto MIDIMAP_KEY_PLAYING = "playing";
+constexpr auto MIDIMAP_KEY_PLAYING_INAUDIBLE = "playing_inaudible";
+constexpr auto MIDIMAP_KEY_STOPPING = "stopping";
+constexpr auto MIDIMAP_KEY_STOPPED = "stopped";
+constexpr auto MIDIMAP_KEY_CHANNEL = "channel";
+constexpr auto MIDIMAP_KEY_MESSAGE = "message";
#endif
*
* ---------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
" "};
+const char* recTriggerModeOff_xpm[] = {
+"13 13 8 1",
+" c #242523",
+". c #272826",
+"+ c #2C2827",
+"@ c #292B28",
+"# c #493E3F",
+"$ c #6A595B",
+"% c #896E6D",
+"& c #B08E8E",
+"@...........@",
+". .",
+". #$$$$$$$# .",
+". +%&&&&&%+ .",
+". +%&&&%+ .",
+". +%&%+ .",
+". +&+ .",
+". +%&%+ .",
+". +%&&&%+ .",
+". +%&&&&&%+ .",
+". #$$$$$$$# .",
+". .",
+"@...........@"};
+
+
+const char* recTriggerModeOn_xpm[] = {
+"13 13 9 1",
+" c None",
+". c #4D4F4C",
+"+ c #544F4E",
+"@ c #675C5C",
+"# c #6A5F5F",
+"$ c #7D6B6E",
+"% c #827072",
+"& c #967B7A",
+"* c #B18E8F",
+".............",
+".............",
+"..@$$$$$$$@..",
+"..+&*****&+..",
+"...+&***&+...",
+"....+&*&+....",
+".....+*+.....",
+"....+&*&+....",
+"...+&***&+...",
+"..+&*****&+..",
+"..#%%%%%%%#..",
+".............",
+"............."};
+
+
const char* zoomInOff_xpm[] = {
"18 18 8 1",
" c None",
*
* ---------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
extern const char* metronomeOff_xpm[];
extern const char* metronomeOn_xpm[];
+extern const char* recTriggerModeOff_xpm[];
+extern const char* recTriggerModeOn_xpm[];
+
extern const char* inputRecOn_xpm[];
extern const char* inputRecOff_xpm[];
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <thread>
+#include <atomic>
#include <ctime>
+#include <atomic>
#ifdef __APPLE__
#include <pwd.h>
#endif
#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 "../gui/dialogs/mainWindow.h"
+#include "../gui/dialogs/warnings.h"
#include "../glue/main.h"
#include "mixer.h"
#include "wave.h"
#include "mixerHandler.h"
#include "patch.h"
#include "conf.h"
+#include "pluginManager.h"
#include "pluginHost.h"
#include "recorder.h"
+#include "recManager.h"
#include "midiMapConf.h"
#include "kernelMidi.h"
#include "kernelAudio.h"
{
namespace
{
-std::thread videoThread;
+std::thread UIThread_;
/* -------------------------------------------------------------------------- */
-void videoThreadCallback_()
+void UIThreadCallback_()
{
while (G_quit.load() == false) {
if (m::kernelAudio::getStatus())
- gu_refreshUI();
+ u::gui::refreshUI();
u::time::sleep(G_GUI_REFRESH_RATE);
}
}
void initAudio_()
{
- kernelAudio::openDevice();
- clock::init(conf::samplerate, conf::midiTCfps);
+ kernelAudio::openDevice();
+ clock::init(conf::samplerate, conf::midiTCfps);
mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
recorder::init(&mixer::mutex);
+ recManager::init(&mixer::mutex);
#ifdef WITH_VST
- /* If with Jack don't use buffer size stored in Conf. Use real buffersize
- from the soundcard (kernelAudio::realBufsize). */
-
- if (conf::soundSystem == G_SYS_API_JACK)
- pluginHost::init(kernelAudio::getRealBufSize(), conf::samplerate);
- else
- pluginHost::init(conf::buffersize, conf::samplerate);
-
- pluginHost::sortPlugins(conf::pluginSortMethod);
+ pluginManager::init(conf::samplerate, kernelAudio::getRealBufSize());
+ pluginManager::sortPlugins(static_cast<pluginManager::SortMethod>(conf::pluginSortMethod));
+ pluginHost::init(kernelAudio::getRealBufSize());
#endif
G_MainWin = new gdMainWindow(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT, "", argc, argv);
G_MainWin->resize(conf::mainWindowX, conf::mainWindowY, conf::mainWindowW,
- conf::mainWindowH);
+ conf::mainWindowH);
- gu_updateMainWinLabel(patch::name == "" ? G_DEFAULT_PATCH_NAME : patch::name);
+ u::gui::updateMainWinLabel(patch::name == "" ? G_DEFAULT_PATCH_NAME : patch::name);
if (!kernelAudio::getStatus())
gdAlert("Your soundcard isn't configured correctly.\n"
"Check the configuration and restart Giada.");
- gu_updateControls();
+ u::gui::updateControls();
- videoThread = std::thread(videoThreadCallback_);
+ UIThread_ = std::thread(UIThreadCallback_);
}
#ifdef WITH_VST
pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex);
- pluginHost::close();
+ pluginHost::close();
gu_log("[init] PluginHost cleaned up\n");
#endif
void shutdownGUI_()
{
- gu_closeAllSubwindows();
- videoThread.join();
+ u::gui::closeAllSubwindows();
+ UIThread_.join();
gu_log("[init] All subwindows and UI thread closed\n");
}
void startup(int argc, char** argv)
{
time_t t;
- time (&t);
- gu_log("[init] Giada " G_VERSION_STR " - %s", ctime(&t));
+ time (&t);
+ gu_log("[init] Giada %s - %s", G_VERSION_STR, ctime(&t));
initConf_();
initAudio_();
/* -------------------------------------------------------------------------- */
+void closeMainWindow()
+{
+ if (!gdConfirmWin("Warning", "Quit Giada: are you sure?"))
+ return;
+
+ G_MainWin->hide();
+ delete G_MainWin;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
void shutdown()
{
G_quit.store(true);
shutdownAudio_();
- gu_log("[init] Giada " G_VERSION_STR " closed\n\n");
+ gu_log("[init] Giada %s closed\n\n", G_VERSION_STR);
gu_logClose();
}
}}} // giada::m::init
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace init
{
void startup(int argc, char** argv);
+void closeMainWindow();
void shutdown();
}}} // giada::m::init
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
namespace
{
-bool status = false;
-int api = 0;
-RtMidiOut* midiOut = nullptr;
-RtMidiIn* midiIn = nullptr;
-unsigned numOutPorts = 0;
-unsigned numInPorts = 0;
+bool status_ = false;
+int api_ = 0;
+RtMidiOut* midiOut_ = nullptr;
+RtMidiIn* midiIn_ = nullptr;
+unsigned numOutPorts_ = 0;
+unsigned numInPorts_ = 0;
-static void callback(double t, std::vector<unsigned char>* msg, void* data)
+static void callback_(double t, vector<unsigned char>* msg, void* data)
{
if (msg->size() < 3) {
//gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
/* -------------------------------------------------------------------------- */
-void sendMidiLightningInitMsgs()
+void sendMidiLightningInitMsgs_()
{
for(unsigned i=0; i<midimap::initCommands.size(); i++) {
midimap::message_t msg = midimap::initCommands.at(i);
}
}
-}; // {anonymous}
+} // {anonymous}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
-void setApi(int _api)
+void setApi(int api)
{
- api = _api;
- gu_log("[KM] using system 0x%x\n", api);
+ api_ = api;
+ gu_log("[KM] using system 0x%x\n", api_);
}
int openOutDevice(int port)
{
try {
- midiOut = new RtMidiOut((RtMidi::Api) api, "Giada MIDI Output");
- status = true;
+ midiOut_ = new RtMidiOut((RtMidi::Api) api_, "Giada MIDI Output");
+ status_ = true;
}
catch (RtMidiError &error) {
gu_log("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
- status = false;
+ status_ = false;
return 0;
}
/* print output ports */
- numOutPorts = midiOut->getPortCount();
- gu_log("[KM] %d output MIDI ports found\n", numOutPorts);
- for (unsigned i=0; i<numOutPorts; i++)
+ numOutPorts_ = midiOut_->getPortCount();
+ gu_log("[KM] %d output MIDI ports found\n", numOutPorts_);
+ for (unsigned i=0; i<numOutPorts_; i++)
gu_log(" %d) %s\n", i, getOutPortName(i).c_str());
/* try to open a port, if enabled */
- if (port != -1 && numOutPorts > 0) {
+ if (port != -1 && numOutPorts_ > 0) {
try {
- midiOut->openPort(port, getOutPortName(port));
+ midiOut_->openPort(port, getOutPortName(port));
gu_log("[KM] MIDI out port %d open\n", port);
/* TODO - it shold send midiLightning message only if there is a map loaded
and available in midimap:: */
- sendMidiLightningInitMsgs();
+ sendMidiLightningInitMsgs_();
return 1;
}
- catch (RtMidiError &error) {
+ catch (RtMidiError& error) {
gu_log("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str());
- status = false;
+ status_ = false;
return 0;
}
}
int openInDevice(int port)
{
try {
- midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input");
- status = true;
+ midiIn_ = new RtMidiIn((RtMidi::Api) api_, "Giada MIDI input");
+ status_ = true;
}
catch (RtMidiError &error) {
gu_log("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
- status = false;
+ status_ = false;
return 0;
}
/* print input ports */
- numInPorts = midiIn->getPortCount();
- gu_log("[KM] %d input MIDI ports found\n", numInPorts);
- for (unsigned i=0; i<numInPorts; i++)
+ numInPorts_ = midiIn_->getPortCount();
+ gu_log("[KM] %d input MIDI ports found\n", numInPorts_);
+ for (unsigned i=0; i<numInPorts_; i++)
gu_log(" %d) %s\n", i, getInPortName(i).c_str());
/* try to open a port, if enabled */
- if (port != -1 && numInPorts > 0) {
+ if (port != -1 && numInPorts_ > 0) {
try {
- midiIn->openPort(port, getInPortName(port));
- midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
+ midiIn_->openPort(port, getInPortName(port));
+ midiIn_->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
gu_log("[KM] MIDI in port %d open\n", port);
- midiIn->setCallback(&callback);
+ midiIn_->setCallback(&callback_);
return 1;
}
- catch (RtMidiError &error) {
+ catch (RtMidiError& error) {
gu_log("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str());
- status = false;
+ status_ = false;
return 0;
}
}
string getOutPortName(unsigned p)
{
- try { return midiOut->getPortName(p); }
+ try { return midiOut_->getPortName(p); }
catch (RtMidiError &error) { return ""; }
}
string getInPortName(unsigned p)
{
- try { return midiIn->getPortName(p); }
+ try { return midiIn_->getPortName(p); }
catch (RtMidiError &error) { return ""; }
}
void send(uint32_t data)
{
- if (!status)
+ if (!status_)
return;
vector<unsigned char> msg(1, getB1(data));
msg.push_back(getB2(data));
msg.push_back(getB3(data));
- midiOut->sendMessage(&msg);
+ midiOut_->sendMessage(&msg);
gu_log("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
}
void send(int b1, int b2, int b3)
{
- if (!status)
+ if (!status_)
return;
vector<unsigned char> msg(1, b1);
if (b3 != -1)
msg.push_back(b3);
- midiOut->sendMessage(&msg);
+ midiOut_->sendMessage(&msg);
//gu_log("[KM] send msg=(%X %X %X)\n", b1, b2, b3);
}
/* -------------------------------------------------------------------------- */
-unsigned countInPorts()
-{
- return numInPorts;
-}
-
-
-unsigned countOutPorts()
-{
- return numOutPorts;
-}
-
+unsigned countInPorts() { return numInPorts_; }
+unsigned countOutPorts() { return numOutPorts_; }
+bool getStatus() { return status_; }
/* -------------------------------------------------------------------------- */
return (iValue & (~chanMask)) | (channel << 24);
}
-
-/* -------------------------------------------------------------------------- */
-
-
-bool getStatus()
-{
- return status;
-}
-
}}}; // giada::m::kernelMidi::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#ifdef WITH_VST
- pthread_mutex_lock(&pluginHost::mutex_midi);
+ pthread_mutex_lock(&pluginHost::mutex);
addVstMidiEvent(midiEventFlat.getRaw(), 0);
- pthread_mutex_unlock(&pluginHost::mutex_midi);
+ pthread_mutex_unlock(&pluginHost::mutex);
#endif
}
}
-
-/* -------------------------------------------------------------------------- */
-
-
-bool MidiChannel::canInputRec()
-{
- return false; // midi channels don't handle input audio
-}
-
}} // giada::m::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
void readPatch(const std::string& basePath, const patch::channel_t& pch) override;
void writePatch(int i, bool isProject) override;
void receiveMidi(const MidiEvent& midiEvent) override;
- bool canInputRec() override;
/* sendMidi
- * send Midi event to the outside world. */
+ Sends Midi event to the outside world. */
void sendMidi(const Action* a, int localFrame);
#ifdef WITH_VST
/* addVstMidiEvent
- * Add a new Midi event to the midiEvent stack fom a composite uint32_t raw
- * Midi event. LocalFrame is the offset: it tells where to put the event
- * inside the buffer. */
+ Adds a new Midi event to the midiEvent stack fom a composite uint32_t raw
+ Midi event. LocalFrame is the offset: it tells where to put the event
+ inside the buffer. */
void addVstMidiEvent(uint32_t msg, int localFrame);
void process(MidiChannel* ch, AudioBuffer& out, const AudioBuffer& in, bool audible)
{
#ifdef WITH_VST
- pluginHost::processStack(ch->buffer, pluginHost::CHANNEL, ch);
+ pluginHost::processStack(ch->buffer, pluginHost::StackType::CHANNEL, ch);
#endif
/* Process the plugin stack first, then quit if the channel is muted/soloed.
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
namespace
{
-/* cb_midiLearn, cb_data
+/* cb_midiLearn, cb_data_
Callback prepared by the gdMidiGrabber window and called by midiDispatcher. It
contains things to do once the midi message has been stored. */
-cb_midiLearn* cb_learn = nullptr;
-void* cb_data = nullptr;
+cb_midiLearn* cb_learn_ = nullptr;
+void* cb_data_ = nullptr;
+
+std::function<void()> signalCb_ = nullptr;
/* -------------------------------------------------------------------------- */
#ifdef WITH_VST
-void processPlugins(Channel* ch, const MidiEvent& midiEvent)
+void processPlugins_(Channel* ch, const MidiEvent& midiEvent)
{
uint32_t pure = midiEvent.getRawNoVelocity();
indexes match both the structure of Channel::midiInPlugins and
vector<Plugin*>* plugins. */
- vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
+ std::vector<Plugin*> plugins = pluginHost::getStack(pluginHost::StackType::CHANNEL, ch);
- for (Plugin* plugin : *plugins) {
+ for (Plugin* plugin : plugins) {
for (unsigned k=0; k<plugin->midiInParams.size(); k++) {
uint32_t midiInParam = plugin->midiInParams.at(k);
if (pure != midiInParam)
/* -------------------------------------------------------------------------- */
-void processChannels(const MidiEvent& midiEvent)
+void processChannels_(const MidiEvent& midiEvent)
{
uint32_t pure = midiEvent.getRawNoVelocity();
#ifdef WITH_VST
/* Process learned plugins parameters. */
- processPlugins(ch, midiEvent);
+ processPlugins_(ch, midiEvent);
#endif
/* -------------------------------------------------------------------------- */
-void processMaster(const MidiEvent& midiEvent)
+void processMaster_(const MidiEvent& midiEvent)
{
uint32_t pure = midiEvent.getRawNoVelocity();
}
else if (pure == conf::midiInActionRec) {
gu_log(" >>> actionRec (master) (pure=0x%X)\n", pure);
- c::io::startStopActionRec(false);
+ c::io::toggleActionRec(false);
}
else if (pure == conf::midiInInputRec) {
gu_log(" >>> inputRec (master) (pure=0x%X)\n", pure);
- c::io::startStopInputRec(false);
+ c::io::toggleInputRec(false);
}
else if (pure == conf::midiInMetronome) {
gu_log(" >>> metronome (master) (pure=0x%X)\n", pure);
- c::transport::startStopMetronome(false);
+ c::transport::toggleMetronome(false);
}
else if (pure == conf::midiInVolumeIn) {
float vf = midiEvent.getVelocity() / 127.0f;
gu_log(" >>> input volume (master) (pure=0x%X, value=%d, float=%f)\n",
pure, midiEvent.getVelocity(), vf);
- glue_setInVol(vf, false);
+ c::main::setInVol(vf, false);
}
else if (pure == conf::midiInVolumeOut) {
float vf = midiEvent.getVelocity() / 127.0f;
gu_log(" >>> output volume (master) (pure=0x%X, value=%d, float=%f)\n",
pure, midiEvent.getVelocity(), vf);
- glue_setOutVol(vf, false);
+ c::main::setOutVol(vf, false);
}
else if (pure == conf::midiInBeatDouble) {
gu_log(" >>> sequencer x2 (master) (pure=0x%X)\n", pure);
- glue_beatsMultiply();
+ c::main::beatsMultiply();
}
else if (pure == conf::midiInBeatHalf) {
gu_log(" >>> sequencer /2 (master) (pure=0x%X)\n", pure);
- glue_beatsDivide();
+ c::main::beatsDivide();
}
}
+
+/* -------------------------------------------------------------------------- */
+
+
+void triggerSignalCb_()
+{
+ if (signalCb_ == nullptr)
+ return;
+ signalCb_();
+ signalCb_ = nullptr;
+}
} // {anonymous}
void startMidiLearn(cb_midiLearn* cb, void* data)
{
- cb_learn = cb;
- cb_data = data;
+ cb_learn_ = cb;
+ cb_data_ = data;
}
void stopMidiLearn()
{
- cb_learn = nullptr;
- cb_data = nullptr;
+ cb_learn_ = nullptr;
+ cb_data_ = nullptr;
}
then each channel in the stack. This way incoming signals don't get processed
by glue_* when MIDI learning is on. */
- if (cb_learn)
- cb_learn(midiEvent.getRawNoVelocity(), cb_data);
+ if (cb_learn_)
+ cb_learn_(midiEvent.getRawNoVelocity(), cb_data_);
else {
- processMaster(midiEvent);
- processChannels(midiEvent);
+ processMaster_(midiEvent);
+ processChannels_(midiEvent);
+ triggerSignalCb_();
}
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void setSignalCallback(std::function<void()> f)
+{
+ signalCb_ = f;
+}
+
}}}; // giada::m::midiDispatcher::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define G_MIDI_DISPATCHER_H
-#ifdef __APPLE__ // our Clang still doesn't know about cstdint (c++11 stuff)
- #include <stdint.h>
-#else
- #include <cstdint>
-#endif
+#include <functional>
+#include <cstdint>
namespace giada {
void dispatch(int byte1, int byte2, int byte3);
+void setSignalCallback(std::function<void()> f);
}}}; // giada::m::midiDispatcher::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
json_t *jInitCommand;
json_array_foreach(jInitCommands, commandIndex, jInitCommand) {
- string indexStr = "init command " + gu_iToString(commandIndex);
+ string indexStr = "init command " + u::string::iToString(commandIndex);
if (!storager::checkObject(jInitCommand, indexStr.c_str()))
return 0;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <cstring>
#include "../deps/rtaudio-mod/RtAudio.h"
#include "../utils/log.h"
+#include "../utils/math.h"
#include "wave.h"
#include "kernelAudio.h"
#include "recorder.h"
{
namespace
{
-constexpr Frame TICKSIZE = 38;
-
-float tock[TICKSIZE] = {
- 0.059033, 0.117240, 0.173807, 0.227943, 0.278890, 0.325936,
- 0.368423, 0.405755, 0.437413, 0.462951, 0.482013, 0.494333,
- 0.499738, 0.498153, 0.489598, 0.474195, 0.452159, 0.423798,
- 0.389509, 0.349771, 0.289883, 0.230617, 0.173194, 0.118739,
- 0.068260, 0.022631, -0.017423, -0.051339, -0.078721, -0.099345,
- -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
- -0.070862, -0.048844
-};
-
-float tick[TICKSIZE] = {
- 0.175860, 0.341914, 0.488904, 0.608633, 0.694426, 0.741500,
- 0.747229, 0.711293, 0.635697, 0.524656, 0.384362, 0.222636,
- 0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
- -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
- -0.201360, -0.067752, 0.052194, 0.151746, 0.226280, 0.273493,
- 0.293425, 0.288307, 0.262252, 0.220811, 0.170435, 0.117887,
- 0.069639, 0.031320
-};
-
-AudioBuffer vChanInput; // virtual channel for recording
-AudioBuffer vChanInToOut; // virtual channel in->out bridge (hear what you're playin)
-
-Frame tickTracker = 0;
-Frame tockTracker = 0;
-bool tickPlay = false;
-bool tockPlay = false;
+struct Metronome
+{
+ static constexpr Frame CLICK_SIZE = 38;
+
+ float beat[CLICK_SIZE] = {
+ 0.059033, 0.117240, 0.173807, 0.227943, 0.278890, 0.325936,
+ 0.368423, 0.405755, 0.437413, 0.462951, 0.482013, 0.494333,
+ 0.499738, 0.498153, 0.489598, 0.474195, 0.452159, 0.423798,
+ 0.389509, 0.349771, 0.289883, 0.230617, 0.173194, 0.118739,
+ 0.068260, 0.022631, -0.017423, -0.051339, -0.078721, -0.099345,
+ -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
+ -0.070862, -0.048844
+ };
+
+ float bar[CLICK_SIZE] = {
+ 0.175860, 0.341914, 0.488904, 0.608633, 0.694426, 0.741500,
+ 0.747229, 0.711293, 0.635697, 0.524656, 0.384362, 0.222636,
+ 0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
+ -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
+ -0.201360, -0.067752, 0.052194, 0.151746, 0.226280, 0.273493,
+ 0.293425, 0.288307, 0.262252, 0.220811, 0.170435, 0.117887,
+ 0.069639, 0.031320
+ };
+
+ Frame tracker = 0;
+ bool running = false;
+ bool playBar = false;
+ bool playBeat = false;
+
+ void render(AudioBuffer& outBuf, bool& process, float* data, Frame f)
+ {
+ process = true;
+ for (int i=0; i<outBuf.countChannels(); i++)
+ outBuf[f][i] += data[tracker];
+ if (++tracker > Metronome::CLICK_SIZE) {
+ process = false;
+ tracker = 0;
+ }
+ }
+} metronome_;
+
+/* vChanInput
+Virtual channel for input recording. */
+
+AudioBuffer vChanInput_;
+
+/* vChanInToOut
+Virtual channel in->out bridge (hear what you're playin). */
+
+AudioBuffer vChanInToOut_;
/* inputTracker
-Sample position while recording. */
+Frame position while recording. */
+
+Frame inputTracker_ = 0;
-Frame inputTracker = 0;
+std::function<void()> signalCb_ = nullptr;
/* -------------------------------------------------------------------------- */
-/* computePeak */
-void computePeak(const AudioBuffer& buf, float& peak, Frame frame)
+void computePeak_(const AudioBuffer& buf, std::atomic<float>& peak)
{
- for (int i=0; i<buf.countChannels(); i++)
- if (buf[frame][i] > peak)
- peak = buf[frame][i];
+ for (int i=0; i<buf.countFrames(); i++)
+ for (int j=0; j<buf.countChannels(); j++)
+ if (buf[i][j] > peak.load())
+ peak.store(buf[i][j]);
}
/* lineInRec
Records from line in. */
-void lineInRec(const AudioBuffer& inBuf, unsigned frame)
+void lineInRec_(const AudioBuffer& inBuf)
{
if (!mh::hasArmedSampleChannels() || !kernelAudio::isInputEnabled() || !recording)
return;
- /* Delay comp: wait until waitRec reaches delayComp. WaitRec returns to 0 in
- mixerHandler, as soon as the recording ends. */
-
- if (waitRec < conf::delayComp) {
- waitRec++;
- return;
- }
-
- for (int i=0; i<vChanInput.countChannels(); i++)
- vChanInput[inputTracker][i] += inBuf[frame][i] * inVol; // adding: overdub!
-
- inputTracker++;
- if (inputTracker >= clock::getFramesInLoop())
- inputTracker = 0;
+ for (int i=0; i<inBuf.countFrames(); i++, inputTracker_++)
+ for (int j=0; j<inBuf.countChannels(); j++) {
+ if (inputTracker_ >= clock::getFramesInLoop())
+ inputTracker_ = 0;
+ vChanInput_[inputTracker_][j] += inBuf[i][j] * inVol.load(); // adding: overdub!
+ }
}
/* -------------------------------------------------------------------------- */
-/* ProcessLineIn
+/* processLineIn
Computes line in peaks, plus handles "hear what you're playin'" thing. */
-void processLineIn(const AudioBuffer& inBuf, unsigned frame)
+void processLineIn_(const AudioBuffer& inBuf)
{
if (!kernelAudio::isInputEnabled())
return;
- computePeak(inBuf, peakIn, frame);
+ computePeak_(inBuf, peakIn);
+
+ if (signalCb_ != nullptr && u::math::linearToDB(peakIn) > conf::recTriggerLevel) {
+ signalCb_();
+ signalCb_ = nullptr;
+ }
/* "hear what you're playing" - process, copy and paste the input buffer onto
the output buffer. */
if (inToOut)
- for (int i=0; i<vChanInToOut.countChannels(); i++)
- vChanInToOut[frame][i] = inBuf[frame][i] * inVol;
+ for (int i=0; i<vChanInToOut_.countFrames(); i++)
+ for (int j=0; j<vChanInToOut_.countChannels(); j++)
+ vChanInToOut_[i][j] = inBuf[i][j] * inVol.load();
}
/* prepareBuffers
Cleans up every buffer, both in Mixer and in channels. */
-void prepareBuffers(AudioBuffer& outBuf)
+void prepareBuffers_(AudioBuffer& outBuf)
{
outBuf.clear();
- vChanInToOut.clear();
+ vChanInToOut_.clear();
for (Channel* channel : channels)
channel->prepareBuffer(clock::isRunning());
}
/* doQuantize
Computes quantization on 'rewind' button and all channels. */
-void doQuantize(unsigned frame)
+void doQuantize_(unsigned frame)
{
/* Nothing to do if quantizer disabled or a quanto has not passed yet. */
}
-/* -------------------------------------------------------------------------- */
-
-/* renderMetronome
-Generates metronome when needed and pastes it to the output buffer. */
-
-void renderMetronome(AudioBuffer& outBuf, unsigned frame)
-{
- if (tockPlay) {
- for (int i=0; i<outBuf.countChannels(); i++)
- outBuf[frame][i] += tock[tockTracker];
- tockTracker++;
- if (tockTracker >= TICKSIZE-1) {
- tockPlay = false;
- tockTracker = 0;
- }
- }
- if (tickPlay) {
- for (int i=0; i<outBuf.countChannels(); i++)
- outBuf[frame][i] += tick[tickTracker];
- tickTracker++;
- if (tickTracker >= TICKSIZE-1) {
- tickPlay = false;
- tickTracker = 0;
- }
- }
-}
-
-
/* -------------------------------------------------------------------------- */
/* renderIO
Final processing stage. Take each channel and process it (i.e. copy its
content to the output buffer). Process plugins too, if any. */
-void renderIO(AudioBuffer& outBuf, const AudioBuffer& inBuf)
+void renderIO_(AudioBuffer& outBuf, const AudioBuffer& inBuf)
{
for (Channel* channel : channels)
channel->process(outBuf, inBuf, isChannelAudible(channel), clock::isRunning());
#ifdef WITH_VST
- pluginHost::processStack(outBuf, pluginHost::MASTER_OUT);
- pluginHost::processStack(vChanInToOut, pluginHost::MASTER_IN);
+ pluginHost::processStack(outBuf, pluginHost::StackType::MASTER_OUT);
+ pluginHost::processStack(vChanInToOut_, pluginHost::StackType::MASTER_IN);
#endif
}
/* limitOutput
Applies a very dumb hard limiter. */
-void limitOutput(AudioBuffer& outBuf, unsigned frame)
+void limitOutput_(AudioBuffer& outBuf)
{
- for (int i=0; i<outBuf.countChannels(); i++)
- if (outBuf[frame][i] > 1.0f)
- outBuf[frame][i] = 1.0f;
- else if (outBuf[frame][i] < -1.0f)
- outBuf[frame][i] = -1.0f;
+ if (!conf::limitOutput)
+ return;
+ for (int i=0; i<outBuf.countFrames(); i++)
+ for (int j=0; j<outBuf.countChannels(); j++)
+ if (outBuf[i][j] > 1.0f) outBuf[i][j] = 1.0f;
+ else if (outBuf[i][j] < -1.0f) outBuf[i][j] = -1.0f;
}
Last touches after the output has been rendered: apply inToOut if any, apply
output volume. */
-void finalizeOutput(AudioBuffer& outBuf, unsigned frame)
+void finalizeOutput_(AudioBuffer& outBuf)
{
- /* Merge vChanInToOut, if enabled. */
-
- if (inToOut)
- outBuf.copyFrame(frame, vChanInToOut[frame]);
-
- for (int i=0; i<outBuf.countChannels(); i++)
- outBuf[frame][i] *= outVol;
+ for (int i=0; i<outBuf.countFrames(); i++)
+ for (int j=0; j<outBuf.countChannels(); j++) {
+ if (inToOut) // Merge vChanInToOut_, if enabled
+ outBuf[i][j] += vChanInToOut_[i][j];
+ outBuf[i][j] *= outVol.load();
+ }
}
/* -------------------------------------------------------------------------- */
-void renderMetronome()
+void renderMetronome_(AudioBuffer& outBuf, Frame f)
{
- if (!metronome)
+ if (!metronome_.running)
return;
- if (clock::isOnBar() || clock::isOnFirstBeat())
- tickPlay = true;
+
+ if (clock::isOnBar() || metronome_.playBar)
+ metronome_.render(outBuf, metronome_.playBar, metronome_.bar, f);
else
- if (clock::isOnBeat())
- tockPlay = true;
+ if (clock::isOnBeat() || metronome_.playBeat)
+ metronome_.render(outBuf, metronome_.playBeat, metronome_.beat, f);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void parseEvents_(Frame f)
+{
+ FrameEvents fe;
+ fe.frameLocal = f;
+ fe.frameGlobal = clock::getCurrentFrame();
+ fe.doQuantize = clock::getQuantize() == 0 || !clock::quantoHasPassed();
+ fe.onBar = clock::isOnBar();
+ fe.onFirstBeat = clock::isOnFirstBeat();
+ fe.quantoPassed = clock::quantoHasPassed();
+ fe.actions = recorder::getActionsOnFrame(clock::getCurrentFrame());
+
+ for (Channel* channel : channels)
+ channel->parseEvents(fe);
}
}; // {anonymous}
std::vector<Channel*> channels;
-bool recording = false;
-bool ready = true;
-float outVol = G_DEFAULT_OUT_VOL;
-float inVol = G_DEFAULT_IN_VOL;
-float peakOut = 0.0f;
-float peakIn = 0.0f;
-bool metronome = false;
-int waitRec = 0;
-bool rewindWait = false;
-bool hasSolos = false;
-bool inToOut = false;
+bool recording = false;
+bool ready = true;
+bool metronome = false;
+int waitRec = 0;
+bool rewindWait = false;
+bool hasSolos = false;
+bool inToOut = false;
+std::atomic<float> outVol(G_DEFAULT_OUT_VOL);
+std::atomic<float> inVol(G_DEFAULT_IN_VOL);
+std::atomic<float> peakOut(0.0);
+std::atomic<float> peakIn(0.0);
pthread_mutex_t mutex;
void init(Frame framesInSeq, Frame framesInBuffer)
{
- /* Allocate virtual input channels. vChanInput has variable size: it depends
+ /* Allocate virtual input channels. vChanInput_ has variable size: it depends
on how many frames there are in sequencer. */
- vChanInput.alloc(framesInSeq, G_MAX_IO_CHANS);
- vChanInToOut.alloc(framesInBuffer, G_MAX_IO_CHANS);
+ vChanInput_.alloc(framesInSeq, G_MAX_IO_CHANS);
+ vChanInToOut_.alloc(framesInBuffer, G_MAX_IO_CHANS);
gu_log("[Mixer::init] buffers ready - framesInSeq=%d, framesInBuffer=%d\n",
framesInSeq, framesInBuffer);
void allocVirtualInput(Frame frames)
{
- vChanInput.alloc(frames, G_MAX_IO_CHANS);
+ vChanInput_.alloc(frames, G_MAX_IO_CHANS);
}
if (!ready)
return 0;
- pthread_mutex_lock(&mutex);
-
#ifdef __linux__
clock::recvJackSync();
#endif
if (kernelAudio::isInputEnabled())
in.setData((float*) inBuf, bufferSize, G_MAX_IO_CHANS);
- peakOut = 0.0f; // reset peak calculator
- peakIn = 0.0f; // reset peak calculator
-
- prepareBuffers(out);
-
- // TODO - move lock here
-
- for (unsigned j=0; j<bufferSize; j++) {
- processLineIn(in, j); // TODO - can go outside this loop
+ peakOut.store(0.0); // reset peak calculator
+ peakIn.store(0.0); // reset peak calculator
- if (clock::isRunning()) {
- FrameEvents fe;
- fe.frameLocal = j;
- fe.frameGlobal = clock::getCurrentFrame();
- fe.doQuantize = clock::getQuantize() == 0 || !clock::quantoHasPassed();
- fe.onBar = clock::isOnBar();
- fe.onFirstBeat = clock::isOnFirstBeat();
- fe.quantoPassed = clock::quantoHasPassed();
- fe.actions = recorder::getActionsOnFrame(clock::getCurrentFrame());
+ prepareBuffers_(out);
+ processLineIn_(in);
- for (Channel* channel : channels)
- channel->parseEvents(fe);
+ pthread_mutex_lock(&mutex);
- lineInRec(in, j); // TODO - can go outside this loop
- doQuantize(j);
- renderMetronome();
- clock::incrCurrentFrame();
+ if (clock::isActive()) {
+ for (unsigned j=0; j<bufferSize; j++) {
+ if (clock::isRunning()) {
+ parseEvents_(j);
+ doQuantize_(j);
+ }
clock::sendMIDIsync();
+ clock::incrCurrentFrame();
+ renderMetronome_(out, j);
}
+ lineInRec_(in);
}
-
- renderIO(out, in);
- // TODO - move unlock here
+ renderIO_(out, in);
- /* Post processing. */
- for (unsigned j=0; j<bufferSize; j++) {
- finalizeOutput(out, j);
- if (conf::limitOutput)
- limitOutput(out, j);
- computePeak(out, peakOut, j);
- renderMetronome(out, j);
- }
+ pthread_mutex_unlock(&mutex);
+
+ /* Post processing */
+
+ finalizeOutput_(out);
+ limitOutput_(out);
+ computePeak_(out, peakOut);
/* Unset data in buffers. If you don't do this, buffers go out of scope and
destroy memory allocated by RtAudio ---> havoc. */
out.setData(nullptr, 0, 0);
- in.setData(nullptr, 0, 0);
-
- pthread_mutex_unlock(&mutex);
+ in.setData (nullptr, 0, 0);
return 0;
}
void close()
{
- clock::stop();
+ clock::setStatus(ClockStatus::STOPPED);
while (channels.size() > 0)
mh::deleteChannel(channels.at(0));
pthread_mutex_destroy(&mutex);
}
-
/* -------------------------------------------------------------------------- */
return !hasSolos || (hasSolos && ch->solo);
}
+bool isMetronomeOn() { return metronome_.running; }
+
/* -------------------------------------------------------------------------- */
void startInputRec()
{
- /* Start inputTracker from the current frame, not the beginning. */
- recording = true;
- inputTracker = clock::getCurrentFrame();
+ /* Start inputTracker_ from the current frame, not the beginning. */
+ recording = true;
+ inputTracker_ = clock::getCurrentFrame();
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void toggleMetronome()
+{
+ metronome_.running = !metronome_.running;
}
+
+void setMetronome(bool v)
+{
+ metronome_.running = v;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void setSignalCallback(std::function<void()> f)
+{
+ signalCb_ = f;
+}
+
+
/* -------------------------------------------------------------------------- */
continue;
SampleChannel* sch = static_cast<SampleChannel*>(ch);
if (sch->armed)
- sch->wave->copyData(vChanInput[0], vChanInput.countFrames());
+ sch->wave->copyData(vChanInput_[0], vChanInput_.countFrames());
}
- vChanInput.clear();
+ vChanInput_.clear();
}
}}}; // giada::m::mixer::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define G_MIXER_H
+#include <atomic>
#include <pthread.h>
+#include <functional>
#include <vector>
#include "recorder.h"
#include "types.h"
extern std::vector<Channel*> channels;
-extern bool recording; // is recording something?
+extern bool recording; // is recording something?
extern bool ready;
-extern float outVol;
-extern float inVol;
-extern float peakOut;
-extern float peakIn;
-extern bool metronome;
-extern int waitRec; // delayComp guard
-extern bool rewindWait; // rewind guard, if quantized
+extern bool rewindWait; // rewind guard, if quantized
extern bool hasSolos; // more than 0 channels soloed
+extern std::atomic<float> outVol;
+extern std::atomic<float> inVol;
+extern std::atomic<float> peakOut;
+extern std::atomic<float> peakIn;
/* inToOut
Copy, process and paste the input into the output, in order to obtain a "hear
Called by mixerHandler on stopInputRec(). */
void mergeVirtualInput();
+
+void toggleMetronome();
+bool isMetronomeOn();
+void setMetronome(bool v);
+
+void setSignalCallback(std::function<void()> f);
}}} // giada::m::mixer::;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
* -------------------------------------------------------------------------- */
+#include <cassert>
#include <vector>
#include <algorithm>
#include "../utils/fs.h"
#include "../utils/string.h"
#include "../utils/log.h"
+#include "../utils/vector.h"
#include "../glue/main.h"
#include "../glue/channel.h"
#include "kernelMidi.h"
#include "const.h"
#include "init.h"
#include "pluginHost.h"
+#include "pluginManager.h"
#include "plugin.h"
#include "waveFx.h"
#include "conf.h"
{
#ifdef WITH_VST
-int readPatchPlugins(vector<patch::plugin_t>* list, int type)
+int readPatchPlugins_(const vector<patch::plugin_t>& list, pluginHost::StackType t)
{
int ret = 1;
- for (unsigned i=0; i<list->size(); i++) {
- patch::plugin_t *ppl = &list->at(i);
- // TODO use glue_addPlugin()
- Plugin *plugin = pluginHost::addPlugin(ppl->path.c_str(), type,
- &mixer::mutex, nullptr);
- if (plugin != nullptr) {
- plugin->setBypass(ppl->bypass);
- for (unsigned j=0; j<ppl->params.size(); j++)
- plugin->setParameter(j, ppl->params.at(j));
+ for (const patch::plugin_t& ppl : list) {
+ std::unique_ptr<Plugin> p = pluginManager::makePlugin(ppl.path);
+ if (p != nullptr) {
+ p->setBypass(ppl.bypass);
+ for (unsigned j=0; j<ppl.params.size(); j++)
+ p->setParameter(j, ppl.params.at(j));
+ pluginHost::addPlugin(std::move(p), t, &mixer::mutex, nullptr);
ret &= 1;
}
else
Channel* ch = channelManager::create(type, kernelAudio::getRealBufSize(),
conf::inputMonitorDefaultOn);
- while (true) {
- if (pthread_mutex_trylock(&mixer::mutex) != 0)
- continue;
- mixer::channels.push_back(ch);
- pthread_mutex_unlock(&mixer::mutex);
- break;
- }
+ pthread_mutex_lock(&mixer::mutex);
+ mixer::channels.push_back(ch);
+ pthread_mutex_unlock(&mixer::mutex);
ch->index = getNewChanIndex();
gu_log("[addChannel] channel index=%d added, type=%d, total=%d\n",
void deleteChannel(Channel* target)
{
- while (true) {
- if (pthread_mutex_trylock(&mixer::mutex) != 0)
- continue;
- auto it = std::find(mixer::channels.begin(), mixer::channels.end(), target);
- if (it != mixer::channels.end())
- mixer::channels.erase(it);
- pthread_mutex_unlock(&mixer::mutex);
- return;
- }
+ int index = u::vector::indexOf(mixer::channels, target);
+ assert(index != -1);
+
+ pthread_mutex_lock(&mixer::mutex);
+ delete mixer::channels.at(index);
+ mixer::channels.erase(mixer::channels.begin() + index);
+ pthread_mutex_unlock(&mixer::mutex);
}
/* -------------------------------------------------------------------------- */
-bool hasLogicalSamples()
-{
- for (const Channel* ch : mixer::channels)
- if (ch->hasLogicalData())
- return true;
- return false;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool hasEditedSamples()
-{
- for (const Channel* ch : mixer::channels)
- if (ch->hasEditedData())
- return true;
- return false;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
void stopSequencer()
{
- clock::stop();
+ clock::setStatus(ClockStatus::STOPPED);
for (Channel* ch : mixer::channels)
ch->stopBySeq(conf::chansStopOnSeqHalt);
}
{
mixer::ready = false;
- mixer::outVol = patch::masterVolOut;
- mixer::inVol = patch::masterVolIn;
+ mixer::outVol.store(patch::masterVolOut);
+ mixer::inVol.store(patch::masterVolIn);
clock::setBpm(patch::bpm);
clock::setBars(patch::bars);
clock::setBeats(patch::beats);
clock::setQuantize(patch::quantize);
clock::updateFrameBars();
- mixer::metronome = patch::metronome;
+ mixer::setMetronome(patch::metronome);
#ifdef WITH_VST
- readPatchPlugins(&patch::masterInPlugins, pluginHost::MASTER_IN);
- readPatchPlugins(&patch::masterOutPlugins, pluginHost::MASTER_OUT);
+ readPatchPlugins_(patch::masterInPlugins, pluginHost::StackType::MASTER_IN);
+ readPatchPlugins_(patch::masterOutPlugins, pluginHost::StackType::MASTER_OUT);
#endif
bool startInputRec()
{
- int channelsReady = 0;
+ if (!hasRecordableSampleChannels())
+ return false;
for (Channel* ch : mixer::channels) {
/* Allocate empty sample for the current channel. */
- Wave* wave = nullptr;
- string name = string("TAKE-" + gu_iToString(patch::lastTakeId++)); // Increase lastTakeId
+ string name = string("TAKE-" + u::string::iToString(patch::lastTakeId++));
+ string nameExt = name + ".wav";
- waveManager::createEmpty(clock::getFramesInLoop(), G_MAX_IO_CHANS,
- conf::samplerate, name + ".wav", &wave);
-
- sch->pushWave(wave);
+ sch->pushWave(waveManager::createEmpty(clock::getFramesInLoop(),
+ G_MAX_IO_CHANS, conf::samplerate, nameExt));
sch->name = name;
- channelsReady++;
- gu_log("[startInputRec] start input recs using chan %d with size %d "
+ gu_log("[startInputRec] start input recs using Channel %d with size %d "
"on frame=%d\n", sch->index, clock::getFramesInLoop(), clock::getCurrentFrame());
}
- /** FIXME: mixer::startInputRec() should be called before wave allocation */
- /** FIXME: mixer::startInputRec() should be called before wave allocation */
- /** FIXME: mixer::startInputRec() should be called before wave allocation */
- if (channelsReady == 0)
- return false;
mixer::startInputRec();
return true;
}
{
mixer::mergeVirtualInput();
mixer::recording = false;
- mixer::waitRec = 0; // in case delay compensation is in use
for (Channel* ch : mixer::channels)
ch->stopInputRec(clock::getCurrentFrame());
bool hasArmedSampleChannels()
{
- for (const Channel* ch : mixer::channels)
- if (ch->type == ChannelType::SAMPLE && ch->armed)
- return true;
- return false;
+ return std::any_of(mixer::channels.begin(), mixer::channels.end(), [](const Channel* ch)
+ {
+ return ch->type == ChannelType::SAMPLE && ch->armed;
+ });
+}
+
+
+bool hasRecordableSampleChannels()
+{
+ return std::any_of(mixer::channels.begin(), mixer::channels.end(), [](const Channel* ch)
+ {
+ return ch->canInputRec();
+ });
+}
+
+
+bool hasLogicalSamples()
+{
+ return std::any_of(mixer::channels.begin(), mixer::channels.end(), [](const Channel* ch)
+ {
+ return ch->hasLogicalData();
+ });
+}
+
+
+bool hasEditedSamples()
+{
+ return std::any_of(mixer::channels.begin(), mixer::channels.end(), [](const Channel* ch)
+ {
+ return ch->hasEditedData();
+ });
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
Channel* getChannelByIndex(int i);
-/* hasLogicalSamples
-True if 1 or more samples are logical (memory only, such as takes) */
-
-bool hasLogicalSamples();
-
-/* hasEditedSamples
-True if 1 or more samples was edited via gEditor */
-
-bool hasEditedSamples();
-
/* stopSequencer
Stops the sequencer, with special case if samplesStopOnSeqHalt is true. */
/* startInputRec - record from line in
Creates a new empty wave in the first available channels. Returns false if
-something went wrong. */
+there are no available channels. */
bool startInputRec();
bool uniqueSamplePath(const SampleChannel* skip, const std::string& p);
+/* hasLogicalSamples
+True if 1 or more samples are logical (memory only, such as takes) */
+
+bool hasLogicalSamples();
+
+/* hasEditedSamples
+True if 1 or more samples was edited via gEditor */
+
+bool hasEditedSamples();
+
/* hasArmedSampleChannels
-Tells whether Mixer has one or more sample channels armed for input
-recording. */
+Tells whether Mixer has one or more Sample Channels armed for input recording. */
bool hasArmedSampleChannels();
+
+/* hasRecordableSampleChannels
+Tells whether Mixer has one or more recordable Sample Channels, that is:
+a) armed; b) empty (no Wave). */
+
+bool hasRecordableSampleChannels();
}}} // giada::m::mh::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
json_t* jChannel;
json_array_foreach(jChannels, channelIndex, jChannel) {
- string channelIndexStr = "channel " + gu_iToString(channelIndex);
+ string channelIndexStr = "channel " + u::string::iToString(channelIndex);
if (!storager::checkObject(jChannel, channelIndexStr.c_str()))
return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_BEGIN, channel.begin)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_END, channel.end)) return 0;
if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_BOOST, channel.boost)) return 0;
- if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, channel.recActive)) return 0;
+ if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_READ_ACTIONS, channel.readActions)) return 0;
if (!storager::setFloat (jChannel, PATCH_KEY_CHANNEL_PITCH, channel.pitch)) return 0;
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;
json_t* jColumn;
json_array_foreach(jColumns, columnIndex, jColumn) {
- string columnIndexStr = "column " + gu_iToString(columnIndex);
+ string columnIndexStr = "column " + u::string::iToString(columnIndex);
if (!storager::checkObject(jColumn, columnIndexStr.c_str()))
return 0;
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BEGIN, json_integer(channel.begin));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_END, json_integer(channel.end));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BOOST, json_real(channel.boost));
- json_object_set_new(jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, json_integer(channel.recActive));
+ json_object_set_new(jChannel, PATCH_KEY_CHANNEL_READ_ACTIONS, json_integer(channel.readActions));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PITCH, json_real(channel.pitch));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INPUT_MONITOR, json_boolean(channel.inputMonitor));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, json_integer(channel.midiInReadActions));
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
int begin;
int end;
float boost;
- int recActive;
+ int readActions; // TODO - should be bool
float pitch;
bool inputMonitor;
uint32_t midiInReadActions;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace giada {
namespace m
{
-int Plugin::idGenerator = 1;
+int Plugin::m_idGenerator = 1;
/* -------------------------------------------------------------------------- */
-Plugin::Plugin(juce::AudioPluginInstance* plugin, double samplerate,
- int buffersize)
- : ui (nullptr),
- plugin(plugin),
- id (idGenerator++),
- bypass(false)
+Plugin::Plugin(juce::AudioPluginInstance* plugin, double samplerate, int buffersize)
+: m_ui (nullptr),
+ m_plugin(plugin),
+ m_id (m_idGenerator++),
+ m_bypass(false)
{
using namespace juce;
-
+
/* Init midiInParams. All values are empty (0x0): they will be filled during
midi learning process. */
- const OwnedArray<AudioProcessorParameter>& params = plugin->getParameters();
+ const OwnedArray<AudioProcessorParameter>& params = m_plugin->getParameters();
for (int i=0; i<params.size(); i++)
midiInParams.push_back(0x0);
- plugin->prepareToPlay(samplerate, buffersize);
+ m_buffer.setSize(G_MAX_IO_CHANS, buffersize);
+
+ /* Try to set the main bus to the current number of channels. In the future
+ this setup will be performed manually through a proper channel matrix. */
- gu_log("[Plugin] plugin initialized and ready. MIDI input params: %lu\n",
+ juce::AudioProcessor::Bus* outBus = getMainBus(BusType::OUT);
+ juce::AudioProcessor::Bus* inBus = getMainBus(BusType::IN);
+ if (outBus != nullptr) outBus->setNumberOfChannels(G_MAX_IO_CHANS);
+ if (inBus != nullptr) inBus->setNumberOfChannels(G_MAX_IO_CHANS);
+
+ m_plugin->prepareToPlay(samplerate, buffersize);
+
+ gu_log("[Plugin] plugin initialized and ready. MIDI input params: %lu\n",
midiInParams.size());
}
Plugin::~Plugin()
{
closeEditor();
- plugin->suspendProcessing(true);
- plugin->releaseResources();
+ m_plugin->suspendProcessing(true);
+ m_plugin->releaseResources();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+juce::AudioProcessor::Bus* Plugin::getMainBus(BusType b) const
+{
+ const bool isInput = static_cast<bool>(b);
+ for (int i=0; i<m_plugin->getBusCount(isInput); i++)
+ if (m_plugin->getBus(isInput, i)->isMain())
+ return m_plugin->getBus(isInput, i);
+ return nullptr;
+}
+
+
+int Plugin::countMainOutChannels() const
+{
+ juce::AudioProcessor::Bus* b = getMainBus(BusType::OUT);
+ assert(b != nullptr);
+ return b->getNumberOfChannels();
}
void Plugin::showEditor(void* parent)
{
- ui = plugin->createEditorIfNeeded();
- if (ui == nullptr) {
+ m_ui = m_plugin->createEditorIfNeeded();
+ if (m_ui == nullptr) {
gu_log("[Plugin::showEditor] unable to create editor!\n");
return;
}
- ui->setOpaque(true);
- ui->addToDesktop(0, parent);
+ m_ui->setOpaque(true);
+ m_ui->addToDesktop(0, parent);
}
bool Plugin::isEditorOpen() const
{
- return ui != nullptr && ui->isVisible() && ui->isOnDesktop();
+ return m_ui != nullptr && m_ui->isVisible() && m_ui->isOnDesktop();
}
string Plugin::getUniqueId() const
{
- return plugin->getPluginDescription().createIdentifierString().toStdString();
+ return m_plugin->getPluginDescription().createIdentifierString().toStdString();
}
int Plugin::getNumParameters() const
{
- return plugin->getParameters().size();
+ return m_plugin->getParameters().size();
}
float Plugin::getParameter(int paramIndex) const
{
- return plugin->getParameters()[paramIndex]->getValue();
+ return m_plugin->getParameters()[paramIndex]->getValue();
}
void Plugin::setParameter(int paramIndex, float value) const
{
- plugin->getParameters()[paramIndex]->setValue(value);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Plugin::prepareToPlay(double samplerate, int buffersize) const
-{
- plugin->prepareToPlay(samplerate, buffersize);
+ m_plugin->getParameters()[paramIndex]->setValue(value);
}
string Plugin::getName() const
{
- return plugin->getName().toStdString();
+ return m_plugin->getName().toStdString();
}
bool Plugin::isSuspended() const
{
- return plugin->isSuspended();
+ return m_plugin->isSuspended();
}
bool Plugin::acceptsMidi() const
{
- return plugin->acceptsMidi();
+ return m_plugin->acceptsMidi();
}
/* -------------------------------------------------------------------------- */
-bool Plugin::isBypassed() const { return bypass; }
-void Plugin::toggleBypass() { bypass = !bypass; }
-void Plugin::setBypass(bool b) { bypass = b; }
+bool Plugin::isBypassed() const { return m_bypass; }
+void Plugin::toggleBypass() { m_bypass = !m_bypass; }
+void Plugin::setBypass(bool b) { m_bypass = b; }
/* -------------------------------------------------------------------------- */
-int Plugin::getId() const { return id; }
+int Plugin::getId() const { return m_id; }
/* -------------------------------------------------------------------------- */
-int Plugin::getEditorW() const { assert(ui != nullptr); return ui->getWidth(); }
-int Plugin::getEditorH() const { assert(ui != nullptr); return ui->getHeight(); }
+int Plugin::getEditorW() const { assert(m_ui != nullptr); return m_ui->getWidth(); }
+int Plugin::getEditorH() const { assert(m_ui != nullptr); return m_ui->getHeight(); }
/* -------------------------------------------------------------------------- */
-void Plugin::process(juce::AudioBuffer<float>& b, juce::MidiBuffer m) const
+void Plugin::process(juce::AudioBuffer<float>& out, juce::MidiBuffer m)
{
- plugin->processBlock(b, m);
+ /* If this is not an instrument (i.e. doesn't accept MIDI), copy the
+ incoming buffer data into the temporary one. This way FXes will process
+ existing audio data. Conversely, if the plug-in is an instrument, it
+ generates its own audio data inside a clean m_buffer and we can play more
+ than one plug-in instrument in the same stack, driven by the same set of
+ MIDI events. */
+
+ const bool isInstrument = m_plugin->acceptsMidi();
+
+ if (!isInstrument)
+ m_buffer = out;
+ else
+ m_buffer.clear();
+
+ m_plugin->processBlock(m_buffer, m);
+
+ /* The local buffer is now filled. Let's try to fill the 'out' one as well
+ by taking into account the bus layout - many plug-ins might have mono output
+ and we have a stereo buffer to fill. */
+
+ for (int i=0, j=0; i<out.getNumChannels(); i++) {
+ if (isInstrument)
+ out.addFrom(i, 0, m_buffer, j, 0, m_buffer.getNumSamples());
+ else
+ out.copyFrom(i, 0, m_buffer, j, 0, m_buffer.getNumSamples());
+ if (i < countMainOutChannels() - 1)
+ j++;
+ }
}
int Plugin::getNumPrograms() const
{
- return plugin->getNumPrograms();
+ return m_plugin->getNumPrograms();
}
int Plugin::getCurrentProgram() const
{
- return plugin->getCurrentProgram();
+ return m_plugin->getCurrentProgram();
}
void Plugin::setCurrentProgram(int index) const
{
- plugin->setCurrentProgram(index);
+ m_plugin->setCurrentProgram(index);
}
bool Plugin::hasEditor() const
{
- return plugin->hasEditor();
+ return m_plugin->hasEditor();
}
string Plugin::getProgramName(int index) const
{
- return plugin->getProgramName(index).toStdString();
+ return m_plugin->getProgramName(index).toStdString();
}
string Plugin::getParameterName(int index) const
{
- return plugin->getParameters()[index]->getName(MAX_LABEL_SIZE).toStdString();
+ return m_plugin->getParameters()[index]->getName(MAX_LABEL_SIZE).toStdString();
}
string Plugin::getParameterText(int index) const
{
- return plugin->getParameters()[index]->getCurrentValueAsText().toStdString();
+ return m_plugin->getParameters()[index]->getCurrentValueAsText().toStdString();
}
string Plugin::getParameterLabel(int index) const
{
- return plugin->getParameters()[index]->getLabel().toStdString();
+ return m_plugin->getParameters()[index]->getLabel().toStdString();
}
void Plugin::closeEditor()
{
- delete ui;
- ui = nullptr;
+ delete m_ui;
+ m_ui = nullptr;
}
}} // giada::m::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
class Plugin
{
-private:
-
- static const int MAX_LABEL_SIZE = 64;
-
- static int idGenerator;
-
- juce::AudioProcessorEditor* ui; // gui
- juce::AudioPluginInstance* plugin; // core
-
- int id;
- bool bypass;
-
public:
Plugin(juce::AudioPluginInstance* p, double samplerate, int buffersize);
std::string getUniqueId() const;
- /* process
- Process the plug-in with audio and MIDI data. The audio buffer is a reference:
- it has to be altered by the plug-in itself. Conversely, the MIDI buffer must
- be passed by copy: each plug-in must receive its own copy of the event set, so
- that any attempt to change/clear the MIDI buffer will only modify the local
- copy. */
-
- void process(juce::AudioBuffer<float>& b, juce::MidiBuffer m) const;
-
std::string getName() const;
bool isEditorOpen() const;
bool hasEditor() const;
int getEditorW() const;
int getEditorH() const;
void setParameter(int index, float value) const;
- void prepareToPlay(double samplerate, int buffersize) const;
void setCurrentProgram(int index) const;
bool acceptsMidi() const;
+ /* process
+ Process the plug-in with audio and MIDI data. The audio buffer is a reference:
+ it has to be altered by the plug-in itself. Conversely, the MIDI buffer must
+ be passed by copy: each plug-in must receive its own copy of the event set, so
+ that any attempt to change/clear the MIDI buffer will only modify the local
+ copy. */
+
+ void process(juce::AudioBuffer<float>& b, juce::MidiBuffer m);
+
void showEditor(void* parent);
/* closeEditor
A list of midiIn hex values for parameter automation. */
std::vector<uint32_t> midiInParams;
+
+private:
+
+ enum class BusType { IN = true, OUT = false };
+
+ static const int MAX_LABEL_SIZE = 64;
+
+ static int m_idGenerator;
+
+ juce::AudioProcessorEditor* m_ui; // gui
+ juce::AudioPluginInstance* m_plugin; // core
+ juce::AudioBuffer<float> m_buffer;
+
+ int m_id;
+ bool m_bypass;
+
+ juce::AudioProcessor::Bus* getMainBus(BusType b) const;
+
+ /* countMainOutChannels
+ Returns the current channel layout for the main output bus. */
+
+ int countMainOutChannels() const;
};
}} // giada::m::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <cassert>
#include "../utils/log.h"
-#include "../utils/fs.h"
-#include "../utils/string.h"
+#include "../utils/vector.h"
#include "const.h"
#include "channel.h"
#include "plugin.h"
#include "pluginHost.h"
-using std::vector;
-using std::string;
-
-
namespace giada {
namespace m {
namespace pluginHost
{
namespace
{
-juce::MessageManager* messageManager;
-
-/* pluginFormat
- * Plugin format manager. */
-
-juce::VSTPluginFormat pluginFormat;
-
-/* knownPuginList
- * List of known (i.e. scanned) plugins. */
+juce::MessageManager* messageManager_;
+juce::AudioBuffer<float> audioBuffer_;
-juce::KnownPluginList knownPluginList;
+std::vector<std::unique_ptr<Plugin>> masterOut_;
+std::vector<std::unique_ptr<Plugin>> masterIn_;
-/* unknownPluginList
- * List of unrecognized plugins found in a patch. */
-vector<string> unknownPluginList;
-
-vector<Plugin*> masterOut;
-vector<Plugin*> masterIn;
-
-/* Audio|MidiBuffer
- * Dynamic buffers. */
-
-juce::AudioBuffer<float> audioBuffer;
+/* -------------------------------------------------------------------------- */
-int samplerate;
-int buffersize;
-/* missingPlugins
- * If some plugins from any stack are missing. */
+void processPlugin_(Plugin& p, Channel* ch)
+{
+ if (p.isSuspended() || p.isBypassed())
+ return;
-bool missingPlugins;
+ juce::MidiBuffer events;
+ if (ch != nullptr)
+ events = ch->getPluginMidiEvents();
-void splitPluginDescription(const string& descr, vector<string>& out)
-{
- // input: VST-mda-Ambience-18fae2d2-6d646141 string
- // output: [2-------------] [1-----] [0-----] vector.size() == 3
-
- string chunk = "";
- int count = 2;
- for (int i=descr.length()-1; i >= 0; i--) {
- if (descr[i] == '-' && count != 0) {
- out.push_back(chunk);
- count--;
- chunk = "";
- }
- else
- chunk += descr[i];
- }
- out.push_back(chunk);
+ p.process(audioBuffer_, events);
}
-/* findPluginDescription
-Browses the list of known plug-ins until plug-in with id == 'id' is found.
-Unfortunately knownPluginList.getTypeForIdentifierString(id) doesn't work for
-VSTs: their ID is based on the plug-in file location. E.g.:
-
- /home/vst/mdaAmbience.so -> VST-mdaAmbience-18fae2d2-6d646141
- /home/vst-test/mdaAmbience.so -> VST-mdaAmbience-b328b2f6-6d646141
+/* -------------------------------------------------------------------------- */
-The following function simply drops the first hash code during comparison. */
+/* getStack_
+Returns a vector of unique_ptr's given the stackType. If stackType == CHANNEL
+a pointer to Channel is also required. */
-const juce::PluginDescription* findPluginDescription(const string& id)
+std::vector<std::unique_ptr<Plugin>>& getStack_(StackType t, Channel* ch=nullptr)
{
- vector<string> idParts;
- splitPluginDescription(id, idParts);
-
- for (const juce::PluginDescription* pd : knownPluginList) {
- vector<string> tmpIdParts;
- splitPluginDescription(pd->createIdentifierString().toStdString(), tmpIdParts);
- if (idParts[0] == tmpIdParts[0] && idParts[2] == tmpIdParts[2])
- return pd;
+ switch(t) {
+ case StackType::MASTER_OUT:
+ return masterOut_;
+ case StackType::MASTER_IN:
+ return masterIn_;
+ case StackType::CHANNEL:
+ return ch->plugins;
+ default:
+ assert(false);
}
- return nullptr;
}
+
}; // {anonymous}
/* -------------------------------------------------------------------------- */
-pthread_mutex_t mutex_midi;
+pthread_mutex_t mutex;
/* -------------------------------------------------------------------------- */
void close()
{
- messageManager->deleteInstance();
- pthread_mutex_destroy(&mutex_midi);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init(int buffersize_, int samplerate_)
-{
- messageManager = juce::MessageManager::getInstance();
- audioBuffer.setSize(G_MAX_IO_CHANS, buffersize_);
- samplerate = samplerate_;
- buffersize = buffersize_;
- missingPlugins = false;
- //unknownPluginList.empty();
- loadList(gu_getHomePath() + G_SLASH + "plugins.xml");
-
- pthread_mutex_init(&mutex_midi, nullptr);
-
- gu_log("[pluginHost::init] initialized with buffersize=%d, samplerate=%d\n",
- buffersize, samplerate);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int scanDirs(const string& dirs, const std::function<void(float)>& cb)
-{
- gu_log("[pluginHost::scanDir] requested directories: '%s'\n", dirs.c_str());
- gu_log("[pluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
-
- knownPluginList.clear(); // clear up previous plugins
-
- vector<string> dirVec;
- gu_split(dirs, ";", &dirVec);
-
- juce::VSTPluginFormat format;
- juce::FileSearchPath searchPath;
- for (const string& dir : dirVec)
- searchPath.add(juce::File(dir));
-
- juce::PluginDirectoryScanner scanner(knownPluginList, format, searchPath,
- true, juce::File()); // true: recursive
-
- juce::String name;
- while (scanner.scanNextFile(false, name)) {
- gu_log("[pluginHost::scanDir] scanning '%s'\n", name.toRawUTF8());
- cb(scanner.getProgress());
- }
-
- gu_log("[pluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
- return knownPluginList.getNumTypes();
+ messageManager_->deleteInstance();
+ pthread_mutex_destroy(&mutex);
}
/* -------------------------------------------------------------------------- */
-int saveList(const string& filepath)
+void init(int buffersize)
{
- int out = knownPluginList.createXml()->writeToFile(juce::File(filepath), "");
- if (!out)
- gu_log("[pluginHost::saveList] unable to save plugin list to %s\n", filepath.c_str());
- return out;
-}
-
+ messageManager_ = juce::MessageManager::getInstance();
+ audioBuffer_.setSize(G_MAX_IO_CHANS, buffersize);
-/* -------------------------------------------------------------------------- */
-
-
-int loadList(const string& filepath)
-{
- juce::XmlElement* elem = juce::XmlDocument::parse(juce::File(filepath));
- if (elem) {
- knownPluginList.recreateFromXml(*elem);
- delete elem;
- return 1;
- }
- return 0;
+ pthread_mutex_init(&mutex, nullptr);
}
/* -------------------------------------------------------------------------- */
-Plugin* addPlugin(const string& fid, int stackType, pthread_mutex_t* mutex,
+void addPlugin(std::unique_ptr<Plugin> p, StackType t, pthread_mutex_t* mixerMutex,
Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
-
- /* Initialize plugin. The default mode uses getTypeForIdentifierString,
- falling back to getTypeForFile (deprecated) for old patches (< 0.14.4). */
-
- const juce::PluginDescription* pd = findPluginDescription(fid);
- if (pd == nullptr) {
- gu_log("[pluginHost::addPlugin] no plugin found with fid=%s! Trying with "
- "deprecated mode...\n", fid.c_str());
- pd = knownPluginList.getTypeForFile(fid);
- if (pd == nullptr) {
- gu_log("[pluginHost::addPlugin] still nothing to do, returning unknown plugin\n");
- missingPlugins = true;
- unknownPluginList.push_back(fid);
- return nullptr;
- }
- }
-
- juce::AudioPluginInstance* pi = pluginFormat.createInstanceFromDescription(*pd, samplerate, buffersize);
- if (!pi) {
- gu_log("[pluginHost::addPlugin] unable to create instance with fid=%s!\n", fid.c_str());
- missingPlugins = true;
- return nullptr;
- }
- gu_log("[pluginHost::addPlugin] plugin instance with fid=%s created\n", fid.c_str());
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
- Plugin* p = new Plugin(pi, samplerate, buffersize);
+ gu_log("[pluginHost::addPlugin] load plugin (%s), stack type=%d, stack size=%d\n",
+ p->getName().c_str(), t, stack.size());
- /* Try to inject the plugin as soon as possible. */
-
- while (true) {
- if (pthread_mutex_trylock(mutex) != 0)
- continue;
- pStack->push_back(p);
- pthread_mutex_unlock(mutex);
- break;
- }
-
- gu_log("[pluginHost::addPlugin] plugin id=%s loaded (%s), stack type=%d, stack size=%d\n",
- fid.c_str(), p->getName().c_str(), stackType, pStack->size());
-
- return p;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Plugin* addPlugin(int index, int stackType, pthread_mutex_t* mutex,
- Channel* ch)
-{
- juce::PluginDescription* pd = knownPluginList.getType(index);
- if (pd) {
- gu_log("[pluginHost::addPlugin] plugin found, uid=%s, name=%s...\n",
- pd->createIdentifierString().toRawUTF8(), pd->name.toRawUTF8());
- return addPlugin(pd->createIdentifierString().toStdString(), stackType, mutex, ch);
- }
- gu_log("[pluginHost::addPlugin] no plugins found at index=%d!\n", index);
- return nullptr;
+ pthread_mutex_lock(mixerMutex);
+ stack.push_back(std::move(p));
+ pthread_mutex_unlock(mixerMutex);
}
/* -------------------------------------------------------------------------- */
-vector<Plugin*>* getStack(int stackType, Channel* ch)
+std::vector<Plugin*> getStack(StackType t, Channel* ch)
{
- switch(stackType) {
- case MASTER_OUT:
- return &masterOut;
- case MASTER_IN:
- return &masterIn;
- case CHANNEL:
- return &ch->plugins;
- default:
- return nullptr;
- }
-}
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
+ std::vector<Plugin*> out;
+ for (const std::unique_ptr<Plugin>& p : stack)
+ out.push_back(p.get());
-/* -------------------------------------------------------------------------- */
-
-
-unsigned countPlugins(int stackType, Channel* ch)
-{
- vector<Plugin*>* pStack = getStack(stackType, ch);
- return pStack->size();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int countAvailablePlugins()
-{
- return knownPluginList.getNumTypes();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-unsigned countUnknownPlugins()
-{
- return unknownPluginList.size();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-pluginHost::PluginInfo getAvailablePluginInfo(int i)
-{
- juce::PluginDescription* pd = knownPluginList.getType(i);
- PluginInfo pi;
- pi.uid = pd->fileOrIdentifier.toStdString();
- pi.name = pd->name.toStdString();
- pi.category = pd->category.toStdString();
- pi.manufacturerName = pd->manufacturerName.toStdString();
- pi.format = pd->pluginFormatName.toStdString();
- pi.isInstrument = pd->isInstrument;
- return pi;
+ return out;
}
/* -------------------------------------------------------------------------- */
-bool hasMissingPlugins()
-{
- return missingPlugins;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-string getUnknownPluginInfo(int i)
+int countPlugins(StackType t, Channel* ch)
{
- return unknownPluginList.at(i);
+ return getStack_(t, ch).size();
}
/* -------------------------------------------------------------------------- */
-void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch)
+void freeStack(StackType t, pthread_mutex_t* mixerMutex, Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
- if (pStack->size() == 0)
+ if (stack.size() == 0)
return;
- while (true) {
- if (pthread_mutex_trylock(mutex) != 0)
- continue;
- for (unsigned i=0; i<pStack->size(); i++)
- delete pStack->at(i);
- pStack->clear();
- pthread_mutex_unlock(mutex);
- break;
- }
- gu_log("[pluginHost::freeStack] stack type=%d freed\n", stackType);
+ pthread_mutex_lock(mixerMutex);
+ stack.clear();
+ pthread_mutex_unlock(mixerMutex);
+
+ gu_log("[pluginHost::freeStack] stack type=%d freed\n", t);
}
/* -------------------------------------------------------------------------- */
-void processStack(AudioBuffer& outBuf, int stackType, Channel* ch)
+void processStack(AudioBuffer& outBuf, StackType t, Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
-
- /* Empty stack, stack not found or mixer not ready: do nothing. */
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
- if (pStack == nullptr || pStack->size() == 0)
+ if (stack.size() == 0)
return;
- assert(outBuf.countFrames() == audioBuffer.getNumSamples());
+ assert(outBuf.countFrames() == audioBuffer_.getNumSamples());
/* MIDI channels must not process the current buffer: give them an empty one.
Sample channels and Master in/out want audio data instead: let's convert the
internal buffer from Giada to Juce. */
if (ch != nullptr && ch->type == ChannelType::MIDI)
- audioBuffer.clear();
+ audioBuffer_.clear();
else
for (int i=0; i<outBuf.countFrames(); i++)
for (int j=0; j<outBuf.countChannels(); j++)
- audioBuffer.setSample(j, i, outBuf[i][j]);
-
- /* Hardcore processing. At the end we swap input and output, so that he N-th
- plugin will process the result of the plugin N-1. Part of this loop must be
- guarded by mutexes, i.e. the MIDI process part. You definitely don't want
- a situation like the following one:
- this::processStack()
- [a new midi event comes in from kernelMidi thread]
- channel::clearMidiBuffer()
+ audioBuffer_.setSample(j, i, outBuf[i][j]);
+
+ /* Hardcore processing. Part of this loop must be guarded by mutexes, i.e.
+ the MIDI process part. You definitely don't want a situation like the
+ following one:
+ 1. this::processStack()
+ 2. [a new midi event comes in from kernelMidi thread]
+ 3. channel::clearMidiBuffer()
The midi event in between would be surely lost, deleted by the last call to
- channel::clearMidiBuffer()! */
+ channel::clearMidiBuffer()!
+ TODO - that's why we need a proper queue for MIDI events in input... */
if (ch != nullptr)
- pthread_mutex_lock(&mutex_midi);
-
- for (const Plugin* plugin : *pStack) {
- if (plugin->isSuspended() || plugin->isBypassed())
- continue;
-
- /* If this is a Channel (ch != nullptr) and the current plugin is an
- instrument (i.e. accepts MIDI), don't let it fill the current audio buffer:
- create a new temporary one instead and then merge the result into the main
- one when done. This way each plug-in generates its own audio data and we can
- play more than one plug-in instrument in the same stack, driven by the same
- set of MIDI events. */
-
- if (ch != nullptr && plugin->acceptsMidi()) {
- juce::AudioBuffer<float> tmp(audioBuffer.getNumChannels(), buffersize);
- plugin->process(tmp, ch->getPluginMidiEvents());
- for (int i=0; i<audioBuffer.getNumSamples(); i++)
- for (int j=0; j<audioBuffer.getNumChannels(); j++)
- audioBuffer.addSample(j, i, tmp.getSample(j, i));
- }
- else
- plugin->process(audioBuffer, juce::MidiBuffer()); // Empty MIDI buffer
- }
+ pthread_mutex_lock(&mutex);
+
+ for (std::unique_ptr<Plugin>& plugin : stack)
+ processPlugin_(*plugin.get(), ch);
if (ch != nullptr) {
ch->clearMidiBuffer();
- pthread_mutex_unlock(&mutex_midi);
+ pthread_mutex_unlock(&mutex);
}
/* Converting buffer from Juce to Giada. A note for the future: if we
for (int i=0; i<outBuf.countFrames(); i++)
for (int j=0; j<outBuf.countChannels(); j++)
- outBuf[i][j] = audioBuffer.getSample(j, i);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Plugin* getPluginByIndex(int index, int stackType, Channel* ch)
-{
- vector<Plugin*>* pStack = getStack(stackType, ch);
- if (pStack->size() == 0)
- return nullptr;
- if ((unsigned) index >= pStack->size())
- return nullptr;
- return pStack->at(index);
+ outBuf[i][j] = audioBuffer_.getSample(j, i);
}
/* -------------------------------------------------------------------------- */
-int getPluginIndex(int id, int stackType, Channel* ch)
+Plugin* getPluginByIndex(int index, StackType t, Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
- for (unsigned i=0; i<pStack->size(); i++)
- if (pStack->at(i)->getId() == id)
- return i;
- return -1;
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
+ assert((size_t) index < stack.size());
+ return stack.at(index).get();
}
/* -------------------------------------------------------------------------- */
-void swapPlugin(unsigned indexA, unsigned indexB, int stackType,
- pthread_mutex_t* mutex, Channel* ch)
+int getPluginIndex(int id, StackType t, Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
- while (true) {
- if (pthread_mutex_trylock(mutex) != 0)
- continue;
- std::swap(pStack->at(indexA), pStack->at(indexB));
- pthread_mutex_unlock(mutex);
- gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB);
- return;
- }
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
+ return u::vector::indexOf(stack, [&](const std::unique_ptr<Plugin>& p)
+ {
+ return p->getId() == id;
+ });
}
/* -------------------------------------------------------------------------- */
-int freePlugin(int id, int stackType, pthread_mutex_t* mutex, Channel* ch)
+void swapPlugin(int indexA, int indexB, StackType t, pthread_mutex_t* mixerMutex,
+ Channel* ch)
{
- vector<Plugin*>* pStack = getStack(stackType, ch);
- for (unsigned i=0; i<pStack->size(); i++) {
- Plugin *pPlugin = pStack->at(i);
- if (pPlugin->getId() != id)
- continue;
- while (true) {
- if (pthread_mutex_trylock(mutex) != 0)
- continue;
- delete pPlugin;
- pStack->erase(pStack->begin() + i);
- pthread_mutex_unlock(mutex);
- gu_log("[pluginHost::freePlugin] plugin id=%d removed\n", id);
- return i;
- }
- }
- gu_log("[pluginHost::freePlugin] plugin id=%d not found\n", id);
- return -1;
-}
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
+ pthread_mutex_lock(mixerMutex);
+ std::swap(stack.at(indexA), stack.at(indexB));
+ pthread_mutex_unlock(mixerMutex);
-/* -------------------------------------------------------------------------- */
-
-
-void runDispatchLoop()
-{
- messageManager->runDispatchLoopUntil(10);
- //gu_log("[pluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent());
+ gu_log("[pluginHost::swapPlugin] plugin at index %d and %d swapped\n", indexA, indexB);
}
/* -------------------------------------------------------------------------- */
-void freeAllStacks(vector<Channel*>* channels, pthread_mutex_t* mutex)
+int freePlugin(int id, StackType t, pthread_mutex_t* mixerMutex, Channel* ch)
{
- freeStack(pluginHost::MASTER_OUT, mutex);
- freeStack(pluginHost::MASTER_IN, mutex);
- for (unsigned i=0; i<channels->size(); i++)
- freeStack(pluginHost::CHANNEL, mutex, channels->at(i));
- missingPlugins = false;
- unknownPluginList.clear();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, ch);
-int clonePlugin(Plugin* src, int stackType, pthread_mutex_t* mutex,
- Channel* ch)
-{
- Plugin* p = addPlugin(src->getUniqueId(), stackType, mutex, ch);
- if (!p) {
- gu_log("[pluginHost::clonePlugin] unable to add new plugin to stack!\n");
- return 0;
- }
+ int index = u::vector::indexOf(stack, [&](const std::unique_ptr<Plugin>& p)
+ {
+ return p->getId() == id;
+ });
+ assert(index != -1);
- for (int k=0; k<src->getNumParameters(); k++)
- p->setParameter(k, src->getParameter(k));
+ pthread_mutex_lock(mixerMutex);
+ stack.erase(stack.begin() + index);
+ pthread_mutex_unlock(mixerMutex);
- return 1;
+ gu_log("[pluginHost::freePlugin] plugin id=%d removed\n", id);
+ return index;
}
/* -------------------------------------------------------------------------- */
-bool doesPluginExist(const string& fid)
+void runDispatchLoop()
{
- return pluginFormat.doesPluginStillExist(*knownPluginList.getTypeForFile(fid));
+ messageManager_->runDispatchLoopUntil(10);
}
/* -------------------------------------------------------------------------- */
-void sortPlugins(int method)
+void freeAllStacks(std::vector<Channel*>* channels, pthread_mutex_t* mixerMutex)
{
- switch (method) {
- case sortMethod::NAME:
- knownPluginList.sort(juce::KnownPluginList::SortMethod::sortAlphabetically, true);
- break;
- case sortMethod::CATEGORY:
- knownPluginList.sort(juce::KnownPluginList::SortMethod::sortByCategory, true);
- break;
- case sortMethod::MANUFACTURER:
- knownPluginList.sort(juce::KnownPluginList::SortMethod::sortByManufacturer, true);
- break;
- case sortMethod::FORMAT:
- knownPluginList.sort(juce::KnownPluginList::SortMethod::sortByFormat, true);
- break;
- }
+ freeStack(StackType::MASTER_OUT, mixerMutex);
+ freeStack(StackType::MASTER_IN, mixerMutex);
+ for (Channel* c : *channels)
+ freeStack(StackType::CHANNEL, mixerMutex, c);
}
/* -------------------------------------------------------------------------- */
-void forEachPlugin(int stackType, const Channel* ch, std::function<void(const Plugin* p)> f)
+void forEachPlugin(StackType t, const Channel* ch, std::function<void(const Plugin* p)> f)
{
- /* TODO - Remove const is ugly. This is a temporary workaround until all
- PluginHost functions params will be const-correct. */
- vector<Plugin*>* stack = getStack(stackType, const_cast<Channel*>(ch));
- for (const Plugin* p : *stack)
- f(p);
+ std::vector<std::unique_ptr<Plugin>>& stack = getStack_(t, const_cast<Channel*>(ch));
+ for (const std::unique_ptr<Plugin>& p : stack)
+ f(p.get());
}
-
}}}; // giada::m::pluginHost::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#ifdef WITH_VST
+
#ifndef G_PLUGIN_HOST_H
#define G_PLUGIN_HOST_H
#include <functional>
#include <pthread.h>
#include "../deps/juce-config.h"
-#include "audioBuffer.h"
-
-
namespace giada {
{
class Plugin;
class Channel;
+class AudioBuffer;
namespace pluginHost
{
-enum stackType
-{
- MASTER_OUT,
- MASTER_IN,
- CHANNEL
-};
+enum class StackType { MASTER_OUT, MASTER_IN, CHANNEL };
-enum sortMethod
-{
- NAME,
- CATEGORY,
- MANUFACTURER,
- FORMAT
-};
-
-struct PluginInfo
-{
- std::string uid;
- std::string name;
- std::string category;
- std::string manufacturerName;
- std::string format;
- bool isInstrument;
-};
+extern pthread_mutex_t mutex;
-extern pthread_mutex_t mutex_midi;
-
-void init(int bufSize, int samplerate);
+void init(int buffersize);
void close();
-/* scanDirs
-Parses plugin directories (semicolon-separated) and store list in
-knownPluginList. The callback is called on each plugin found. Used to update the
-main window from the GUI thread. */
-
-int scanDirs(const std::string& paths, const std::function<void(float)>& cb);
-
-/* (save|load)List
- * (Save|Load) knownPluginList (in|from) an XML file. */
-
-int saveList(const std::string& path);
-int loadList(const std::string& path);
-
/* addPlugin
- * Add a new plugin to 'stackType' by unique id or by index in knownPluginList
- * std::vector. Requires:
- * fid - plugin unique file id (i.e. path to dynamic library)
- * stackType - which stack to add plugin to
- * mutex - Mixer.mutex_plugin
- * freq - current audio frequency
- * bufSize - buffer size
- * ch - if stackType == CHANNEL. */
-
-Plugin* addPlugin(const std::string& fid, int stackType, pthread_mutex_t* mutex,
- Channel* ch=nullptr);
-Plugin *addPlugin(int index, int stackType, pthread_mutex_t* mutex,
- Channel* ch=nullptr);
+Adds a new plugin to 'stackType'. */
-/* countPlugins
- * Return size of 'stackType'. */
+void addPlugin(std::unique_ptr<Plugin> p, StackType t, pthread_mutex_t* mutex,
+ Channel* ch=nullptr);
-unsigned countPlugins(int stackType, Channel* ch=nullptr);
-
-/* countAvailablePlugins
- * Return size of knownPluginList. */
-
-int countAvailablePlugins();
-
-/* countUnknownPlugins
- * Return size of unknownPluginList. */
-
-unsigned countUnknownPlugins();
-
-/* getAvailablePluginInfo
- * Return the available plugin information (name, type, ...) from
- * knownPluginList at index 'index'. */
-
-PluginInfo getAvailablePluginInfo(int index);
+/* countPlugins
+Returns the size of 'stackType'. */
-std::string getUnknownPluginInfo(int index);
+int countPlugins(StackType t, Channel* ch=nullptr);
/* freeStack
- * free plugin stack of type 'stackType'. */
+Frees plugin stack of type 'stackType'. */
-void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch=nullptr);
+void freeStack(StackType t, pthread_mutex_t* mutex, Channel* ch=nullptr);
/* processStack
Applies the fx list to the buffer. */
-void processStack(AudioBuffer& outBuf, int stackType, Channel* ch=nullptr);
+void processStack(AudioBuffer& outBuf, StackType t, Channel* ch=nullptr);
/* getStack
-* Return a std::vector <Plugin *> given the stackType. If stackType == CHANNEL
-* a pointer to Channel is also required. */
+Returns a vector of Plugin pointers given the stackType. If stackType == CHANNEL
+a pointer to Channel is also required. */
-std::vector<Plugin*>* getStack(int stackType, Channel* ch=nullptr);
+std::vector<Plugin*> getStack(StackType t, Channel* ch=nullptr);
/* getPluginByIndex */
-Plugin* getPluginByIndex(int index, int stackType, Channel* ch=nullptr);
+Plugin* getPluginByIndex(int index, StackType t, Channel* ch=nullptr);
/* getPluginIndex */
-int getPluginIndex(int id, int stackType, Channel* ch=nullptr);
+int getPluginIndex(int id, StackType t, Channel* ch=nullptr);
/* swapPlugin */
-void swapPlugin(unsigned indexA, unsigned indexB, int stackType,
- pthread_mutex_t* mutex, Channel* ch=nullptr);
+void swapPlugin(int indexA, int indexB, StackType t, pthread_mutex_t* mutex,
+ Channel* ch=nullptr);
/* freePlugin.
Returns the internal stack index of the deleted plugin. */
-int freePlugin(int id, int stackType, pthread_mutex_t *mutex,
- Channel* ch=nullptr);
+int freePlugin(int id, StackType t, pthread_mutex_t* mutex, Channel* ch=nullptr);
/* runDispatchLoop
- * Wakes up plugins' GUI manager for N milliseconds. */
+Wakes up plugins' GUI manager for N milliseconds. */
void runDispatchLoop();
/* freeAllStacks
- * Frees everything. */
+Frees everything. */
void freeAllStacks(std::vector<Channel*>* channels, pthread_mutex_t* mutex);
-/* clonePlugin */
-
-int clonePlugin(Plugin* src, int stackType, pthread_mutex_t* mutex, Channel* ch);
-
-/* doesPluginExist */
-
-bool doesPluginExist(const std::string& fid);
-
-bool hasMissingPlugins();
-
-void sortPlugins(int sortMethod);
-
-void forEachPlugin(int stackType, const Channel* ch, std::function<void(const Plugin* p)> f);
+void forEachPlugin(StackType t, const Channel* ch, std::function<void(const Plugin* p)> f);
}}}; // giada::m::pluginHost::
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+
+#include <cassert>
+#include "../utils/log.h"
+#include "../utils/fs.h"
+#include "../utils/string.h"
+#include "const.h"
+#include "plugin.h"
+#include "pluginManager.h"
+
+
+using std::vector;
+using std::string;
+
+
+namespace giada {
+namespace m {
+namespace pluginManager
+{
+namespace
+{
+int samplerate_;
+int buffersize_;
+
+/* pluginFormat
+Plugin format manager. */
+
+juce::VSTPluginFormat pluginFormat_;
+
+/* knownPuginList
+List of known (i.e. scanned) plugins. */
+
+juce::KnownPluginList knownPluginList_;
+
+/* unknownPluginList
+List of unrecognized plugins found in a patch. */
+
+vector<string> unknownPluginList_;
+
+/* missingPlugins
+If some plugins from any stack are missing. */
+
+bool missingPlugins_;
+
+vector<string> splitPluginDescription_(const string& descr)
+{
+ // input: VST-mda-Ambience-18fae2d2-6d646141 string
+ // output: [2-------------] [1-----] [0-----] vector.size() == 3
+
+ vector<string> out;
+
+ string chunk = "";
+ int count = 2;
+ for (int i=descr.length()-1; i >= 0; i--) {
+ if (descr[i] == '-' && count != 0) {
+ out.push_back(chunk);
+ count--;
+ chunk = "";
+ }
+ else
+ chunk += descr[i];
+ }
+ out.push_back(chunk);
+
+ return out;
+}
+
+
+/* findPluginDescription
+Browses the list of known plug-ins until plug-in with id == 'id' is found.
+Unfortunately knownPluginList_.getTypeForIdentifierString(id) doesn't work for
+VSTs: their ID is based on the plug-in file location. E.g.:
+
+ /home/vst/mdaAmbience.so -> VST-mdaAmbience-18fae2d2-6d646141
+ /home/vst-test/mdaAmbience.so -> VST-mdaAmbience-b328b2f6-6d646141
+
+The following function simply drops the first hash code during comparison. */
+
+const juce::PluginDescription* findPluginDescription_(const string& id)
+{
+ vector<string> idParts = splitPluginDescription_(id);
+
+ for (const juce::PluginDescription* pd : knownPluginList_) {
+ vector<string> tmpIdParts = splitPluginDescription_(pd->createIdentifierString().toStdString());
+ if (idParts[0] == tmpIdParts[0] && idParts[2] == tmpIdParts[2])
+ return pd;
+ }
+ return nullptr;
+}
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+void init(int samplerate, int buffersize)
+{
+ samplerate_ = samplerate;
+ buffersize_ = buffersize;
+ missingPlugins_ = false;
+ unknownPluginList_.clear();
+ loadList(gu_getHomePath() + G_SLASH + "plugins.xml");
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int scanDirs(const string& dirs, const std::function<void(float)>& cb)
+{
+ gu_log("[pluginManager::scanDir] requested directories: '%s'\n", dirs.c_str());
+ gu_log("[pluginManager::scanDir] current plugins: %d\n", knownPluginList_.getNumTypes());
+
+ knownPluginList_.clear(); // clear up previous plugins
+
+ vector<string> dirVec = u::string::split(dirs, ";");
+
+ juce::VSTPluginFormat format;
+ juce::FileSearchPath searchPath;
+ for (const string& dir : dirVec)
+ searchPath.add(juce::File(dir));
+
+ juce::PluginDirectoryScanner scanner(knownPluginList_, format, searchPath,
+ /*recursive=*/true, juce::File());
+
+ juce::String name;
+ while (scanner.scanNextFile(false, name)) {
+ gu_log("[pluginManager::scanDir] scanning '%s'\n", name.toRawUTF8());
+ cb(scanner.getProgress());
+ }
+
+ gu_log("[pluginManager::scanDir] %d plugin(s) found\n", knownPluginList_.getNumTypes());
+ return knownPluginList_.getNumTypes();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int saveList(const string& filepath)
+{
+ int out = knownPluginList_.createXml()->writeToFile(juce::File(filepath), "");
+ if (!out)
+ gu_log("[pluginManager::saveList] unable to save plugin list to %s\n", filepath.c_str());
+ return out;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int loadList(const string& filepath)
+{
+ juce::XmlElement* elem = juce::XmlDocument::parse(juce::File(filepath));
+ if (elem != nullptr) {
+ knownPluginList_.recreateFromXml(*elem);
+ delete elem;
+ return 1;
+ }
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::unique_ptr<Plugin> makePlugin(const string& fid)
+{
+ /* Initialize plugin. The default mode uses getTypeForIdentifierString,
+ falling back to getTypeForFile (deprecated) for old patches (< 0.14.4). */
+
+ const juce::PluginDescription* pd = findPluginDescription_(fid);
+ if (pd == nullptr) {
+ gu_log("[pluginManager::makePlugin] no plugin found with fid=%s! Trying with "
+ "deprecated mode...\n", fid.c_str());
+ pd = knownPluginList_.getTypeForFile(fid);
+ if (pd == nullptr) {
+ gu_log("[pluginManager::makePlugin] still nothing to do, returning unknown plugin\n");
+ missingPlugins_ = true;
+ unknownPluginList_.push_back(fid);
+ return {};
+ }
+ }
+
+ juce::AudioPluginInstance* pi = pluginFormat_.createInstanceFromDescription(*pd, samplerate_, buffersize_);
+ if (!pi) {
+ gu_log("[pluginManager::makePlugin] unable to create instance with fid=%s!\n", fid.c_str());
+ missingPlugins_ = true;
+ return {};
+ }
+ gu_log("[pluginManager::makePlugin] plugin instance with fid=%s created\n", fid.c_str());
+
+ return std::make_unique<Plugin>(pi, samplerate_, buffersize_);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::unique_ptr<Plugin> makePlugin(int index)
+{
+ juce::PluginDescription* pd = knownPluginList_.getType(index);
+
+ if (pd == nullptr)
+ return {};
+
+ gu_log("[pluginManager::makePlugin] plugin found, uid=%s, name=%s...\n",
+ pd->createIdentifierString().toRawUTF8(), pd->name.toRawUTF8());
+
+ return makePlugin(pd->createIdentifierString().toStdString());
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::unique_ptr<Plugin> makePlugin(const Plugin& src)
+{
+ std::unique_ptr<Plugin> p = makePlugin(src.getUniqueId());
+
+ for (int i=0; i<src.getNumParameters(); i++)
+ p->setParameter(i, src.getParameter(i));
+
+ return p;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int countAvailablePlugins()
+{
+ return knownPluginList_.getNumTypes();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+unsigned countUnknownPlugins()
+{
+ return unknownPluginList_.size();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+PluginInfo getAvailablePluginInfo(int i)
+{
+ juce::PluginDescription* pd = knownPluginList_.getType(i);
+ PluginInfo pi;
+ pi.uid = pd->fileOrIdentifier.toStdString();
+ pi.name = pd->name.toStdString();
+ pi.category = pd->category.toStdString();
+ pi.manufacturerName = pd->manufacturerName.toStdString();
+ pi.format = pd->pluginFormatName.toStdString();
+ pi.isInstrument = pd->isInstrument;
+ return pi;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool hasMissingPlugins()
+{
+ return missingPlugins_;
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+string getUnknownPluginInfo(int i)
+{
+ return unknownPluginList_.at(i);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool doesPluginExist(const string& fid)
+{
+ return pluginFormat_.doesPluginStillExist(*knownPluginList_.getTypeForFile(fid));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void sortPlugins(SortMethod method)
+{
+ switch (method) {
+ case SortMethod::NAME:
+ knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortAlphabetically, true);
+ break;
+ case SortMethod::CATEGORY:
+ knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByCategory, true);
+ break;
+ case SortMethod::MANUFACTURER:
+ knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByManufacturer, true);
+ break;
+ case SortMethod::FORMAT:
+ knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByFormat, true);
+ break;
+ }
+}
+
+}}}; // giada::m::pluginManager::
+
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+#ifndef G_PLUGIN_MANAGER_H
+#define G_PLUGIN_MANAGER_H
+
+
+#include "../deps/juce-config.h"
+#include "plugin.h"
+
+
+namespace giada {
+namespace m
+{
+namespace pluginManager
+{
+enum class SortMethod : int
+{
+ NAME = 0, CATEGORY, MANUFACTURER, FORMAT
+};
+
+struct PluginInfo
+{
+ std::string uid;
+ std::string name;
+ std::string category;
+ std::string manufacturerName;
+ std::string format;
+ bool isInstrument;
+};
+
+void init(int samplerate, int buffersize);
+
+/* scanDirs
+Parses plugin directories (semicolon-separated) and store list in
+knownPluginList. The callback is called on each plugin found. Used to update the
+main window from the GUI thread. */
+
+int scanDirs(const std::string& paths, const std::function<void(float)>& cb);
+
+/* (save|load)List
+(Save|Load) knownPluginList (in|from) an XML file. */
+
+int saveList(const std::string& path);
+int loadList(const std::string& path);
+
+/* countAvailablePlugins
+Returns how many plug-ins are ready and available for usage. */
+
+int countAvailablePlugins();
+
+/* countUnknownPlugins
+Returns how many plug-ins are in a unknown/not-found state. */
+
+unsigned countUnknownPlugins();
+
+std::unique_ptr<Plugin> makePlugin(const std::string& fid);
+std::unique_ptr<Plugin> makePlugin(int index);
+std::unique_ptr<Plugin> makePlugin(const Plugin& other);
+
+/* getAvailablePluginInfo
+Returns the available plugin information (name, type, ...) given a plug-in
+index. */
+
+PluginInfo getAvailablePluginInfo(int index);
+
+std::string getUnknownPluginInfo(int index);
+
+bool doesPluginExist(const std::string& fid);
+
+bool hasMissingPlugins();
+
+void sortPlugins(SortMethod sortMethod);
+
+}}}; // giada::m::pluginManager::
+
+
+#endif
+
+#endif // #ifdef WITH_VST
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 "../gui/dispatcher.h"
+#include "../glue/transport.h"
+#include "types.h"
+#include "clock.h"
+#include "kernelAudio.h"
+#include "conf.h"
+#include "channel.h"
+#include "mixer.h"
+#include "mixerHandler.h"
+#include "midiDispatcher.h"
+#include "recorder.h"
+#include "recorderHandler.h"
+#include "recManager.h"
+
+
+namespace giada {
+namespace m {
+namespace recManager
+{
+namespace
+{
+pthread_mutex_t* mixerMutex_ = nullptr;
+bool isActive_ = false;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool startActionRec_()
+{
+ if (!kernelAudio::getStatus())
+ return false;
+ clock::setStatus(ClockStatus::RUNNING);
+ recorder::enable();
+ c::transport::startSeq(/*gui=*/false);
+ return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool startInputRec_()
+{
+ if (!kernelAudio::getStatus() || !mh::startInputRec())
+ return false;
+ c::transport::startSeq(/*gui=*/false);
+ return true;
+}
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+void init(pthread_mutex_t* mixerMutex)
+{
+ mixerMutex_ = mixerMutex;
+ isActive_ = false;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool isActive() { return isActive_; }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool startActionRec(RecTriggerMode mode)
+{
+ isActive_ = true;
+ if (mode == RecTriggerMode::NORMAL)
+ return startActionRec_();
+ if (mode == RecTriggerMode::SIGNAL) {
+ clock::setStatus(ClockStatus::WAITING);
+ clock::rewind();
+ m::midiDispatcher::setSignalCallback(startActionRec_);
+ v::dispatcher::setSignalCallback(startActionRec_);
+ }
+ return true;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void stopActionRec()
+{
+ isActive_ = false;
+
+ if (clock::getStatus() == ClockStatus::WAITING) {
+ clock::setStatus(ClockStatus::STOPPED);
+ return;
+ }
+
+ clock::setStatus(ClockStatus::RUNNING);
+
+ recorder::disable();
+ std::unordered_set<int> channels = recorderHandler::consolidate();
+
+ /* Enable reading actions for Channels that have just been filled with
+ actions. Start reading right away, without checking whether
+ conf::treatRecsAsLoops is enabled or not. */
+
+ pthread_mutex_lock(mixerMutex_);
+ for (int index : channels)
+ mh::getChannelByIndex(index)->startReadingActions(
+ /*treatRecsAsLoops=*/false, /*recsStopOnChanHalt=*/false);
+ pthread_mutex_unlock(mixerMutex_);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool startInputRec(RecTriggerMode mode)
+{
+ if (mode == RecTriggerMode::NORMAL)
+ isActive_ = startInputRec_();
+ if (mode == RecTriggerMode::SIGNAL) {
+ if (!mh::hasRecordableSampleChannels())
+ return false;
+ clock::setStatus(ClockStatus::WAITING);
+ clock::rewind();
+ mixer::setSignalCallback(startInputRec_);
+ isActive_ = true;
+ }
+ return isActive_;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void stopInputRec()
+{
+ isActive_ = false;
+
+ if (clock::getStatus() == ClockStatus::WAITING) {
+ clock::setStatus(ClockStatus::STOPPED);
+ }
+ else {
+ clock::setStatus(ClockStatus::RUNNING);
+ mh::stopInputRec();
+ }
+}
+}}} // giada::m::recManager
\ No newline at end of file
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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_REC_MANAGER_H
+#define G_REC_MANAGER_H
+
+
+#include <pthread.h>
+#include "types.h"
+
+
+namespace giada {
+namespace m {
+namespace recManager
+{
+void init(pthread_mutex_t* mixerMutex);
+
+/* isActive
+Returns true if its ready for recording, whether it is actually recording
+something or is in wait mode for a signal. */
+
+bool isActive();
+
+bool startActionRec(RecTriggerMode m);
+void stopActionRec();
+bool startInputRec(RecTriggerMode m);
+void stopInputRec();
+}}} // giada::m::recManager
+
+#endif
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
ActionMap actions;
-pthread_mutex_t* mixerMutex = nullptr;
-bool active = false;
-int actionId = 0;
+pthread_mutex_t* mixerMutex_ = nullptr;
+bool active_ = false;
+int actionId_ = 0;
/* -------------------------------------------------------------------------- */
void lock_(std::function<void()> f)
{
- assert(mixerMutex != nullptr);
- pthread_mutex_lock(mixerMutex);
+ assert(mixerMutex_ != nullptr);
+ pthread_mutex_lock(mixerMutex_);
f();
- pthread_mutex_unlock(mixerMutex);
+ pthread_mutex_unlock(mixerMutex_);
}
void init(pthread_mutex_t* m)
{
- mixerMutex = m;
- active = false;
- actionId = 0;
+ mixerMutex_ = m;
+ active_ = false;
+ actionId_ = 0;
clearAll();
}
void updateActionId(int id)
{
- if (actionId <= id) // Never decrease it
- actionId = id;
+ if (actionId_ <= id) // Never decrease it
+ actionId_ = id;
}
/* -------------------------------------------------------------------------- */
-bool isActive() { return active; }
-void enable() { active = true; }
-void disable() { active = false; }
+bool isActive() { return active_; }
+void enable() { active_ = true; }
+void disable() { active_ = false; }
/* -------------------------------------------------------------------------- */
lock_([&]
{
- actions[frame].push_back(makeAction(actionId++, channel, frame, event));
+ actions[frame].push_back(makeAction(actionId_++, channel, frame, event));
});
return actions[frame].back();
}
ActionMap temp = actions;
for (const Action* a : as) {
- const_cast<Action*>(a)->id = actionId++;
+ const_cast<Action*>(a)->id = actionId_++;
temp[a->frame].push_back(a); // Memory is already allocated by recorderHandler
}
ActionMap getActionMap() { return actions; }
-int getLatestActionId() { return actionId; }
+int getLatestActionId() { return actionId_; }
/* -------------------------------------------------------------------------- */
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
/* -------------------------------------------------------------------------- */
-void consolidate()
+std::unordered_set<int> consolidate()
{
consolidate_();
recorder::rec(recs_);
+
+ std::unordered_set<int> out;
+ for (const Action* action : recs_)
+ out.insert(action->channel);
+
recs_.clear();
+ return out;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define G_RECORDER_HANDLER_H
+#include <unordered_set>
#include "midiEvent.h"
#include "patch.h"
{
struct Action;
+
namespace recorderHandler
{
bool isBoundaryEnvelopeAction(const Action* a);
void liveRec(int channel, MidiEvent e);
-void consolidate();
+/* consolidate
+Records all live actions. Returns a set of channels indexes that have been
+recorded. */
+
+std::unordered_set<int> consolidate();
void writePatch(int chanIndex, std::vector<patch::action_t>& pactions);
void readPatch(const std::vector<patch::action_t>& pactions);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
tracker (0),
trackerPreview (0),
shift (0),
- qWait (false),
+ quantizing (false),
inputMonitor (inputMonitor),
boost (G_DEFAULT_BOOST),
pitch (G_DEFAULT_PITCH),
SampleChannel::~SampleChannel()
{
- delete wave;
if (rsmp_state != nullptr)
src_delete(rsmp_state);
}
end = src->end;
boost = src->boost;
mode = src->mode;
- qWait = src->qWait;
+ quantizing = src->quantizing;
setPitch(src->pitch);
if (src->wave)
- pushWave(new Wave(*src->wave)); // invoke Wave's copy constructor
+ pushWave(std::make_unique<Wave>(*src->wave)); // invoke Wave's copy constructor
}
volume = G_DEFAULT_VOL;
boost = G_DEFAULT_BOOST;
hasActions = false;
- delete wave;
- wave = nullptr;
+ wave.reset(nullptr);
sendMidiLstatus();
}
/* -------------------------------------------------------------------------- */
-void SampleChannel::pushWave(Wave* w)
+void SampleChannel::pushWave(std::unique_ptr<Wave>&& w)
{
status = ChannelStatus::OFF;
- wave = w;
+ wave = std::move(w);
begin = 0;
end = wave->getSize() - 1;
sendMidiLstatus();
/* -------------------------------------------------------------------------- */
-bool SampleChannel::canInputRec()
+bool SampleChannel::canInputRec() const
{
return wave == nullptr && armed;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define G_SAMPLE_CHANNEL_H
+#include <memory>
#include <functional>
#include <samplerate.h>
#include "types.h"
void empty() override;
void stopBySeq(bool chansStopOnSeqHalt) override;
void rewindBySeq() override;
- bool canInputRec() override;
void stopInputRec(int globalFrame) override;
+ bool canInputRec() const override;
bool hasLogicalData() const override;
bool hasEditedData() const override;
bool hasData() const override;
int fillBuffer(AudioBuffer& dest, int start, int offset);
/* pushWave
- Adds a new wave to an existing channel. */
+ Adds a new wave to this channel. */
- void pushWave(Wave* w);
+ void pushWave(std::unique_ptr<Wave>&& w);
void setPitch(float v);
void setBegin(int f);
ChannelMode mode;
- Wave* wave;
+ std::unique_ptr<Wave> wave;
int tracker; // chan position
int trackerPreview; // chan position for audio preview
int shift;
- bool qWait; // quantizer wait
+ bool quantizing; // quantization in progress
bool inputMonitor;
float boost;
float pitch;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
void rewind_(SampleChannel* ch, int localFrame)
{
- ch->tracker = ch->begin;
- ch->qWait = false; // Was in qWait mode? Reset occured, no more qWait now.
+ ch->tracker = ch->begin;
+ ch->quantizing = false; // No more quantization now
/* On rewind, if channel is playing fill again buffer to create something like
this:
/* Skip if LOOP_ANY, not in quantizer-wait mode or still waiting for the
quantization time to end. */
- if (ch->isAnyLoopMode() || !ch->qWait || !quantoPassed)
+ if (ch->isAnyLoopMode() || !ch->quantizing || !quantoPassed)
return;
switch (ch->status) {
case ChannelStatus::OFF:
ch->status = ChannelStatus::PLAY;
- ch->qWait = false;
ch->tracker += ch->fillBuffer(ch->buffer, ch->tracker, localFrame);
ch->sendMidiLstatus();
+ // ch->quantizing = false is set by sampleChannelRec::quantize()
break;
default:
}
#ifdef WITH_VST
- pluginHost::processStack(ch->buffer, pluginHost::CHANNEL, ch);
+ pluginHost::processStack(ch->buffer, pluginHost::StackType::CHANNEL, ch);
#endif
for (int i=0; i<out.countFrames(); i++) {
default:
/* If quantizing, stop a SINGLE_PRESS immediately. */
- if (ch->mode == ChannelMode::SINGLE_PRESS && ch->qWait)
- ch->qWait = false;
+ if (ch->mode == ChannelMode::SINGLE_PRESS && ch->quantizing)
+ ch->quantizing = false;
break;
}
}
}
else {
if (doQuantize)
- ch->qWait = true;
+ ch->quantizing = true;
else {
ch->status = ChannelStatus::PLAY;
ch->sendMidiLstatus();
case ChannelStatus::PLAY:
if (ch->mode == ChannelMode::SINGLE_RETRIG) {
if (doQuantize)
- ch->qWait = true;
+ ch->quantizing = true;
else
rewind_(ch, localFrame);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
if (!recorderCanRec_(ch))
return;
- /* Disable reading actions while recording SINGLE_PRESS mode. */
+ /* Disable reading actions while recording SINGLE_PRESS mode. Don't let
+ existing actions interfere with the current one being recorded. */
+
if (ch->mode == ChannelMode::SINGLE_PRESS)
ch->readActions = false;
void quantize_(SampleChannel* ch, bool quantoPassed)
{
- /* Skip if LOOP_ANY or not in quantizer-wait mode. Otherwise the quantize wait
- has expired: record the keypress. */
+ /* Skip if in loop mode or not in a quantization stage. Otherwise the
+ quantization wait has expired: record the keypress. */
- if (ch->isAnyLoopMode() || !ch->qWait || !quantoPassed)
- return;
- recordKeyPressAction_(ch);
+ if (!ch->isAnyLoopMode() && ch->quantizing && quantoPassed && ch->status == ChannelStatus::PLAY) {
+ ch->quantizing = false;
+ recordKeyPressAction_(ch);
+ }
}
}; // {anonymous}
channel is in any loop mode, where KEYPRESS and KEYREL are meaningless. */
if (!canQuantize && !ch->isAnyLoopMode() && recorderCanRec_(ch))
- {
recordKeyPressAction_(ch);
-
- /* Why return here? You record an action and then you call ch->start:
- Mixer, which is on another thread, reads your newly recorded action if you
- have readActions == true, and then ch->start kicks in right after it.
- The result: Mixer plays the channel (due to the new action) but the code
- in the switch in start() kills it right away (because the sample is playing).
- Fix: start channel only if you are not recording anything, i.e. let
- Mixer play it. */
-
- if (ch->readActions)
- return false;
- }
return true;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
void parseEvents(SampleChannel* ch, mixer::FrameEvents fe);
/* recordStart
-Records a G_ACTION_KEYPRESS if capable of. Returns true if a start() call can
+Records a 'start' action if capable of. Returns true if a start() call can
be performed. */
bool recordStart(SampleChannel* ch, bool doQuantize);
/* recordKill
-Records a G_ACTION_KILL if capable of. Returns true if a kill() call can
+Records a 'kill' action if capable of. Returns true if a kill() call can
be performed. */
bool recordKill(SampleChannel* ch);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using Pixel = int;
using Frame = int;
+enum class ClockStatus { STOPPED, WAITING, RUNNING };
-enum class ChannelType : int
-{
- SAMPLE = 1, MIDI
-};
-
+enum class ChannelType : int { SAMPLE = 1, MIDI };
enum class ChannelStatus : int
{
ENDING = 1, WAIT, PLAY, OFF, EMPTY, MISSING, WRONG
};
-
enum class ChannelMode : int
{
LOOP_BASIC = 1, LOOP_ONCE, LOOP_REPEAT, LOOP_ONCE_BAR,
SINGLE_BASIC, SINGLE_PRESS, SINGLE_RETRIG, SINGLE_ENDLESS
};
+enum class RecTriggerMode : int { NORMAL = 0, SIGNAL };
enum class PreviewMode : int { NONE = 0, NORMAL, LOOP };
enum class EventType : int { AUTO = 0, MANUAL };
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
+using namespace giada;
Wave::Wave()
if (id == -1)
m_path = p;
else
- m_path = gu_stripExt(p) + "-" + gu_iToString(id) + "." + gu_getExt(p);
+ m_path = gu_stripExt(p) + "-" + u::string::iToString(id) + "." + gu_getExt(p);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
/* -------------------------------------------------------------------------- */
-int create(const string& path, Wave** out)
+Result createFromFile(const string& path)
{
if (path == "" || gu_isDir(path)) {
gu_log("[waveManager::create] malformed path (was '%s')\n", path.c_str());
- return G_RES_ERR_NO_DATA;
+ return { G_RES_ERR_NO_DATA };
}
if (path.size() > FILENAME_MAX)
- return G_RES_ERR_PATH_TOO_LONG;
+ return { G_RES_ERR_PATH_TOO_LONG };
SF_INFO header;
SNDFILE* fileIn = sf_open(path.c_str(), SFM_READ, &header);
if (fileIn == nullptr) {
gu_log("[waveManager::create] unable to read %s. %s\n", path.c_str(), sf_strerror(fileIn));
- return G_RES_ERR_IO;
+ return { G_RES_ERR_IO };
}
if (header.channels > G_MAX_IO_CHANS) {
gu_log("[waveManager::create] unsupported multi-channel sample\n");
- return G_RES_ERR_WRONG_DATA;
+ return { G_RES_ERR_WRONG_DATA };
}
- Wave* wave = new Wave();
+ std::unique_ptr<Wave> wave = std::make_unique<Wave>();
wave->alloc(header.frames, header.channels, header.samplerate, getBits(header), path);
if (sf_readf_float(fileIn, wave->getFrame(0), header.frames) != header.frames)
sf_close(fileIn);
- if (header.channels == 1 && !wfx::monoToStereo(*wave)) {
- delete wave;
- return G_RES_ERR_PROCESSING;
- }
-
- *out = wave;
+ if (header.channels == 1 && !wfx::monoToStereo(*wave))
+ return { G_RES_ERR_PROCESSING };
gu_log("[waveManager::create] new Wave created, %d frames\n", wave->getSize());
- return G_RES_OK;
+ return { G_RES_OK, std::move(wave) };
}
-
/* -------------------------------------------------------------------------- */
-void createEmpty(int frames, int channels, int samplerate, const string& name,
- Wave** out)
+std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate,
+ const string& name)
{
- Wave* wave = new Wave();
+ std::unique_ptr<Wave> wave = std::make_unique<Wave>();
wave->alloc(frames, channels, samplerate, G_DEFAULT_BIT_DEPTH, name);
-
wave->setLogical(true);
- *out = wave;
-
gu_log("[waveManager::createEmpty] new empty Wave created, %d frames\n",
wave->getSize());
+
+ return wave;
}
/* -------------------------------------------------------------------------- */
-void createFromWave(const Wave* src, int a, int b, Wave** out)
+std::unique_ptr<Wave> createFromWave(const Wave* src, int a, int b)
{
int channels = src->getChannels();
int frames = b - a;
- Wave* wave = new Wave();
+ std::unique_ptr<Wave> wave = std::make_unique<Wave>();
wave->alloc(frames, channels, src->getRate(), src->getBits(), src->getPath());
-
wave->copyData(src->getFrame(a), frames);
wave->setLogical(true);
- *out = wave;
-
gu_log("[waveManager::createFromWave] new Wave created, %d frames\n", frames);
+
+ return wave;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <string>
+#include <memory>
class Wave;
namespace m {
namespace waveManager
{
+struct Result
+{
+ int status;
+ std::unique_ptr<Wave> wave;
+};
+
/* create
Creates a new Wave object with data read from file 'path'. */
-int create(const std::string& path, Wave** out);
+Result createFromFile(const std::string& path);
/* createEmpty
Creates a new silent Wave object. */
-void createEmpty(int frames, int channels, int samplerate, const std::string& name,
- Wave** out);
+std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate,
+ const std::string& name);
/* createFromWave
Creates a new Wave from an existing one, copying the data in range a - b. */
-void createFromWave(const Wave* src, int a, int b, Wave** out);
+std::unique_ptr<Wave> createFromWave(const Wave* src, int a, int b);
int resample(Wave* w, int quality, int samplerate);
int save(Wave* w, const std::string& path);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace giada {
namespace m
{
-class Action;
+struct Action;
class SampleChannel;
class MidiChannel;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <cmath>
#include <FL/Fl.H>
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../gui/dialogs/sampleEditor.h"
-#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/warnings.h"
#include "../gui/elems/basics/input.h"
#include "../gui/elems/basics/dial.h"
#include "../gui/elems/sampleEditor/waveTools.h"
conf::samplePath = gu_dirname(fname);
- Wave* wave = nullptr;
- int result = waveManager::create(fname, &wave);
- if (result != G_RES_OK)
- return result;
+ waveManager::Result res = waveManager::createFromFile(fname);
- if (wave->getRate() != conf::samplerate) {
+ if (res.status != G_RES_OK)
+ return res.status;
+
+ if (res.wave->getRate() != conf::samplerate) {
gu_log("[loadChannel] input rate (%d) != system rate (%d), conversion needed\n",
- wave->getRate(), conf::samplerate);
- result = waveManager::resample(wave, conf::rsmpQuality, conf::samplerate);
- if (result != G_RES_OK) {
- delete wave;
- return result;
- }
+ res.wave->getRate(), conf::samplerate);
+ res.status = waveManager::resample(res.wave.get(), conf::rsmpQuality, conf::samplerate);
+ if (res.status != G_RES_OK)
+ return res.status;
}
- ch->pushWave(wave);
+ ch->pushWave(std::move(res.wave));
G_MainWin->keyboard->updateChannel(ch->guiChannel);
- return result;
+ return res.status;
}
recorder::clearChannel(ch->index);
ch->hasActions = false;
#ifdef WITH_VST
- pluginHost::freeStack(pluginHost::CHANNEL, &mixer::mutex, ch);
+ pluginHost::freeStack(pluginHost::StackType::CHANNEL, &mixer::mutex, ch);
#endif
Fl::lock();
G_MainWin->keyboard->deleteChannel(ch->guiChannel);
Fl::unlock();
mh::deleteChannel(ch);
- gu_closeAllSubwindows();
+ u::gui::closeAllSubwindows();
}
/* Changing channel volume? Update wave editor (if it's shown). */
if (!editor) {
- gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->volumeTool->refresh();
void setPitch(m::SampleChannel* ch, float val)
{
ch->setPitch(val);
- gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->pitchTool->refresh();
void setPanning(m::SampleChannel* ch, float val)
{
ch->setPan(val);
- gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->panTool->refresh();
void setBoost(m::SampleChannel* ch, float val)
{
ch->setBoost(val);
- gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->boostTool->refresh();
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/Fl.H>
-#include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/mainWindow.h"
+#include "../gui/dialogs/warnings.h"
+#include "../gui/elems/basics/button.h"
#include "../gui/elems/mainWindow/mainTransport.h"
#include "../gui/elems/mainWindow/mainTimer.h"
#include "../gui/elems/mainWindow/keyboard/keyboard.h"
#include "../utils/log.h"
#include "../utils/math.h"
#include "../core/recorder.h"
+#include "../core/conf.h"
+#include "../core/recManager.h"
#include "../core/kernelAudio.h"
+#include "../core/channel.h"
#include "../core/mixer.h"
#include "../core/mixerHandler.h"
#include "../core/wave.h"
+#include "../core/midiDispatcher.h"
#include "../core/channel.h"
#include "../core/clock.h"
#include "../core/sampleChannel.h"
}
else {
if (ch->recordStart(m::clock::canQuantize()))
- ch->start(0, m::clock::canQuantize(), 0);
+ ch->start(0, m::clock::canQuantize(), velocity);
}
}
/* -------------------------------------------------------------------------- */
-void startStopActionRec(bool gui)
+void toggleActionRec(bool gui)
{
- m::recorder::isActive() ? stopActionRec(gui) : startActionRec(gui);
+ m::recManager::isActive() ? stopActionRec(gui) : startActionRec(gui);
}
void startActionRec(bool gui)
{
- if (m::kernelAudio::getStatus() == false)
- return;
-
- m::recorder::enable();
+ RecTriggerMode triggerMode = static_cast<RecTriggerMode>(m::conf::recTriggerMode);
- if (!m::clock::isRunning())
- c::transport::startSeq(false); // update gui
-
- if (!gui) {
- Fl::lock();
- G_MainWin->mainTransport->updateRecAction(1);
- Fl::unlock();
- }
+ if (!m::recManager::startActionRec(triggerMode))
+ return;
+ if (!gui) Fl::lock();
+ G_MainWin->mainTransport->setRecTriggerModeActive(false);
+ G_MainWin->mainTransport->updatePlay(m::clock::isRunning());
+ G_MainWin->mainTransport->updateRecAction(1);
+ if (!gui) Fl::unlock();
}
void stopActionRec(bool gui)
{
- m::recorder::disable();
- m::recorderHandler::consolidate();
-
- for (m::Channel* ch : m::mixer::channels) {
- if (ch->type == ChannelType::MIDI)
- continue;
- G_MainWin->keyboard->setChannelWithActions(static_cast<geSampleChannel*>(ch->guiChannel));
- if (!ch->readActions && ch->hasActions)
- c::channel::startReadingActions(ch, false);
- }
+ m::recManager::stopActionRec();
- if (!gui) {
- Fl::lock();
- G_MainWin->mainTransport->updateRecAction(0);
- Fl::unlock();
- }
+ if (!gui) Fl::lock();
+ G_MainWin->mainTransport->updateRecAction(0);
+ G_MainWin->mainTransport->setRecTriggerModeActive(true);
+ for (m::Channel* ch : m::mixer::channels)
+ if (ch->type == ChannelType::SAMPLE)
+ G_MainWin->keyboard->setChannelWithActions(static_cast<geSampleChannel*>(ch->guiChannel));
+ if (!gui) Fl::unlock();
- gu_refreshActionEditor(); // in case it's open
+ u::gui::refreshActionEditor(); // in case it's open
}
/* -------------------------------------------------------------------------- */
-void startStopInputRec(bool gui)
+void toggleInputRec(bool gui)
{
- if (m::mixer::recording)
+ if (m::recManager::isActive())
stopInputRec(gui);
else
if (!startInputRec(gui))
/* -------------------------------------------------------------------------- */
-int startInputRec(bool gui)
+bool startInputRec(bool gui)
{
- using namespace giada::m;
-
- if (kernelAudio::getStatus() == false)
- return false;
+ RecTriggerMode triggerMode = static_cast<RecTriggerMode>(m::conf::recTriggerMode);
- if (!mh::startInputRec()) {
- Fl::lock();
+ if (!m::recManager::startInputRec(triggerMode)) {
+ if (!gui) Fl::lock();
G_MainWin->mainTransport->updateRecInput(0); // set it off, anyway
- Fl::unlock();
+ if (!gui) Fl::unlock();
return false;
- }
-
- if (!clock::isRunning())
- transport::startSeq(false); // update gui anyway
+ }
- Fl::lock();
- if (!gui)
- G_MainWin->mainTransport->updateRecInput(1);
- G_MainWin->mainTimer->setLock(true);
- Fl::unlock();
-
- /* Update sample name inside sample channels' main button. This is useless for
- midi channel, but let's do it anyway. */
-
- for (Channel* ch : m::mixer::channels)
- ch->guiChannel->update();
+ if (!gui) Fl::lock();
+ G_MainWin->mainTransport->setRecTriggerModeActive(false);
+ G_MainWin->mainTransport->updatePlay(m::clock::isRunning());
+ G_MainWin->mainTransport->updateRecInput(1);
+ G_MainWin->mainTimer->setLock(true);
+ if (!gui) Fl::unlock();
return true;
}
/* -------------------------------------------------------------------------- */
-int stopInputRec(bool gui)
+void stopInputRec(bool gui)
{
- using namespace giada::m;
-
- mh::stopInputRec();
-
- Fl::lock();
- if (!gui)
- G_MainWin->mainTransport->updateRecInput(0);
- G_MainWin->mainTimer->setLock(false);
- Fl::unlock();
-
- return 1;
+ m::recManager::stopInputRec();
+
+ if (!gui) Fl::lock();
+ G_MainWin->mainTransport->setRecTriggerModeActive(true);
+ G_MainWin->mainTransport->updateRecInput(0);
+ G_MainWin->mainTimer->setLock(false);
+ /* Update sample name inside sample channels' main button. This is useless
+ for MIDI channels, but let's do it anyway. */
+ for (const m::Channel* ch : m::mixer::channels)
+ ch->guiChannel->update();
+ if (!gui) Fl::unlock();
}
}}} // giada::c::io::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace giada {
namespace m
{
-class Plugin;
class Channel;
}
namespace c {
Handles the action recording. If gui == true the signal comes from an user
interaction, otherwise it's a MIDI/Jack/external signal. */
-void startStopActionRec(bool gui=true);
-void startActionRec(bool gui=true);
-void stopActionRec(bool gui=true);
+void toggleActionRec(bool gui=true);
+void startActionRec (bool gui=true);
+void stopActionRec (bool gui=true);
/* start/stopInputRec
Handles the input recording (take). If gui == true the signal comes from an
internal interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
-void startStopInputRec(bool gui=true);
-int startInputRec (bool gui=true);
-int stopInputRec (bool gui=true);
-
+void toggleInputRec(bool gui=true);
+bool startInputRec (bool gui=true);
+void stopInputRec (bool gui=true);
}}} // giada::c::io::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../gui/elems/mainWindow/mainTimer.h"
#include "../gui/elems/mainWindow/keyboard/sampleChannel.h"
#include "../gui/elems/mainWindow/keyboard/keyboard.h"
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../utils/gui.h"
#include "../utils/string.h"
#include "../utils/log.h"
#include "../core/recorderHandler.h"
#include "../core/conf.h"
#include "../core/const.h"
-#ifdef WITH_VST
+#include "../core/pluginManager.h"
#include "../core/pluginHost.h"
-#endif
#include "main.h"
using std::string;
using namespace giada::m;
-
+namespace giada {
+namespace c {
+namespace main
+{
namespace
{
void setBpm_(float f, string s)
recorderHandler::updateBpm(vPre, f, clock::getQuanto());
mixer::allocVirtualInput(clock::getFramesInLoop());
- gu_refreshActionEditor();
- G_MainWin->mainTimer->setBpm(s.c_str());
+ /* This function might get called by Jack callback BEFORE the UI is up
+ and running, that is when G_MainWin == nullptr. */
+
+ if (G_MainWin != nullptr) {
+ u::gui::refreshActionEditor();
+ G_MainWin->mainTimer->setBpm(s.c_str());
+ }
gu_log("[glue::setBpm_] Bpm changed to %s (real=%f)\n", s.c_str(), clock::getBpm());
}
/* -------------------------------------------------------------------------- */
-void glue_setBpm(const char* v1, const char* v2)
+void setBpm(const char* v1, const char* v2)
{
/* Never change this stuff while recording audio */
/* -------------------------------------------------------------------------- */
-void glue_setBpm(float f)
+void setBpm(float f)
{
/* Never change this stuff while recording audio */
/* -------------------------------------------------------------------------- */
-void glue_setBeats(int beats, int bars)
+void setBeats(int beats, int bars)
{
/* Never change this stuff while recording audio */
mixer::allocVirtualInput(clock::getFramesInLoop());
G_MainWin->mainTimer->setMeter(clock::getBeats(), clock::getBars());
- gu_refreshActionEditor(); // in case the action editor is open
+ u::gui::refreshActionEditor(); // in case the action editor is open
}
/* -------------------------------------------------------------------------- */
-void glue_quantize(int val)
+void quantize(int val)
{
clock::setQuantize(val);
}
/* -------------------------------------------------------------------------- */
-void glue_setOutVol(float v, bool gui)
+void setOutVol(float v, bool gui)
{
- mixer::outVol = v;
+ mixer::outVol.store(v);
if (!gui) {
Fl::lock();
G_MainWin->mainIO->setOutVol(v);
/* -------------------------------------------------------------------------- */
-void glue_setInVol(float v, bool gui)
+void setInVol(float v, bool gui)
{
- mixer::inVol = v;
+ mixer::inVol.store(v);
if (!gui) {
Fl::lock();
G_MainWin->mainIO->setInVol(v);
/* -------------------------------------------------------------------------- */
-void glue_clearAllSamples()
+void clearAllSamples()
{
- clock::stop();
+ clock::setStatus(ClockStatus::STOPPED);
for (Channel* ch : mixer::channels) {
ch->empty();
ch->guiChannel->reset();
/* -------------------------------------------------------------------------- */
-void glue_clearAllActions()
+void clearAllActions()
{
recorder::clearAll();
for (Channel* ch : mixer::channels)
ch->hasActions = false;
- gu_updateControls();
+ u::gui::updateControls();
}
/* -------------------------------------------------------------------------- */
-void glue_resetToInitState(bool resetGui, bool createColumns)
+void resetToInitState(bool resetGui, bool createColumns)
{
- gu_closeAllSubwindows();
+ u::gui::closeAllSubwindows();
mixer::close();
clock::init(conf::samplerate, conf::midiTCfps);
mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
recorder::init(&mixer::mutex);
+
#ifdef WITH_VST
pluginHost::freeAllStacks(&mixer::channels, &mixer::mutex);
+ pluginManager::init(conf::samplerate, kernelAudio::getRealBufSize());
#endif
G_MainWin->keyboard->clear();
if (createColumns)
G_MainWin->keyboard->init();
- gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
+ u::gui::updateMainWinLabel(G_DEFAULT_PATCH_NAME);
if (resetGui)
- gu_updateControls();
+ u::gui::updateControls();
}
/* -------------------------------------------------------------------------- */
-void glue_beatsMultiply()
+void beatsMultiply()
{
- glue_setBeats(clock::getBeats() * 2, clock::getBars());
+ setBeats(clock::getBeats() * 2, clock::getBars());
}
-void glue_beatsDivide()
+void beatsDivide()
{
- glue_setBeats(clock::getBeats() / 2, clock::getBars());
+ setBeats(clock::getBeats() / 2, clock::getBars());
}
+
+}}} // giada::c::main::
\ No newline at end of file
* glue
* Intermediate layer GUI <-> CORE.
*
- * How to know if you need another glue_ function? Ask yourself if the
+ * How to know if you need another function? Ask yourself if the
* new action will ever be called via MIDI or keyboard/mouse. If yes,
* put it here.
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
* -------------------------------------------------------------------------- */
-#ifndef G_GLUE_MAIN_H
-#define G_GLUE_MAIN_H
+#ifndef G_MAIN_H
+#define G_MAIN_H
-/* glue_setBpm (1)
+namespace giada {
+namespace c {
+namespace main
+{
+/* setBpm (1)
Sets bpm value from string to float. */
-void glue_setBpm(const char* v1, const char* v2);
+void setBpm(const char* v1, const char* v2);
-/* glue_setBpm (2)
+/* setBpm (2)
Sets bpm value. Usually called from the Jack callback or non-UI components. */
-void glue_setBpm(float v);
+void setBpm(float v);
-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);
-void glue_clearAllSamples();
-void glue_clearAllActions();
+void setBeats(int beats, int bars);
+void quantize(int val);
+void setOutVol(float v, bool gui=true);
+void setInVol(float v, bool gui=true);
+void clearAllSamples();
+void clearAllActions();
/* resetToInitState
Resets Giada to init state. If resetGui also refresh all widgets. If
createColumns also build initial empty columns. */
-void glue_resetToInitState(bool resetGui=true, bool createColumns=true);
+void resetToInitState(bool resetGui=true, bool createColumns=true);
/* beatsDivide/Multiply
Shrinks or enlarges the number of beats by 2. */
-void glue_beatsMultiply();
-void glue_beatsDivide();
+void beatsMultiply();
+void beatsDivide();
+
+}}} // giada::c::main::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/Fl.H>
+#include "../core/pluginManager.h"
#include "../core/pluginHost.h"
#include "../core/mixer.h"
#include "../core/plugin.h"
#include "../core/const.h"
#include "../core/conf.h"
#include "../utils/gui.h"
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../gui/dialogs/pluginWindow.h"
#include "../gui/dialogs/pluginList.h"
-#include "../gui/dialogs/gd_warnings.h"
-#include "../gui/dialogs/gd_config.h"
+#include "../gui/dialogs/warnings.h"
+#include "../gui/dialogs/config.h"
#include "../gui/dialogs/browser/browserDir.h"
#include "plugin.h"
/* Get the parent window first: the plug-in list. Then, if it exists, get
the child window - the actual pluginWindow. */
- gdPluginList* parent = static_cast<gdPluginList*>(gu_getSubwindow(G_MainWin, WID_FX_LIST));
+ gdPluginList* parent = static_cast<gdPluginList*>(u::gui::getSubwindow(G_MainWin, WID_FX_LIST));
if (parent == nullptr)
return nullptr;
- return static_cast<gdPluginWindow*>(gu_getSubwindow(parent, p->getId() + 1));
+ return static_cast<gdPluginWindow*>(u::gui::getSubwindow(parent, p->getId() + 1));
}
} // {anonymous}
/* -------------------------------------------------------------------------- */
-Plugin* addPlugin(Channel* ch, int index, int stackType)
+void addPlugin(Channel* ch, int index, m::pluginHost::StackType t)
{
- if (index >= pluginHost::countAvailablePlugins())
- return nullptr;
- return pluginHost::addPlugin(index, stackType, &mixer::mutex, ch);
+ if (index >= pluginManager::countAvailablePlugins())
+ return;
+ std::unique_ptr<Plugin> p = pluginManager::makePlugin(index);
+ if (p != nullptr)
+ pluginHost::addPlugin(std::move(p), t, &mixer::mutex, ch);
}
/* -------------------------------------------------------------------------- */
-void swapPlugins(Channel* ch, int index1, int index2, int stackType)
+void swapPlugins(Channel* ch, int index1, int index2, m::pluginHost::StackType t)
{
- pluginHost::swapPlugin(index1, index2, stackType, &mixer::mutex,
+ pluginHost::swapPlugin(index1, index2, t, &mixer::mutex,
ch);
}
/* -------------------------------------------------------------------------- */
-void freePlugin(Channel* ch, int index, int stackType)
+void freePlugin(Channel* ch, int index, m::pluginHost::StackType t)
{
- pluginHost::freePlugin(index, stackType, &mixer::mutex, ch);
+ pluginHost::freePlugin(index, t, &mixer::mutex, ch);
}
browser->do_callback();
- gdConfig* configWin = static_cast<gdConfig*>(gu_getSubwindow(G_MainWin, WID_CONFIG));
+ gdConfig* configWin = static_cast<gdConfig*>(u::gui::getSubwindow(G_MainWin, WID_CONFIG));
configWin->refreshVstPath();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#ifdef WITH_VST
+#include "../core/pluginHost.h"
+
+
namespace giada {
namespace m
{
namespace c {
namespace plugin
{
-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 addPlugin(m::Channel* ch, int index, m::pluginHost::StackType t);
+void swapPlugins(m::Channel* ch, int indexP1, int indexP2, m::pluginHost::StackType t);
+void freePlugin(m::Channel* ch, int index, m::pluginHost::StackType t);
void setParameter(m::Plugin* p, int index, float value, bool gui=true);
void setProgram(m::Plugin* p, int index);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <cassert>
-#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/warnings.h"
#include "../gui/elems/mainWindow/keyboard/channel.h"
#include "../gui/elems/mainWindow/keyboard/sampleChannel.h"
#include "../core/const.h"
#include "recorder.h"
-using std::vector;
-using namespace giada;
-
-
namespace giada {
namespace c {
namespace recorder
void updateChannel(geChannel* gch, bool refreshActionEditor)
{
gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
+ if (!gch->ch->hasActions)
+ gch->ch->readActions = false;
+
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
+ u::gui::refreshActionEditor(); // refresh a.editor window, it could be open
}
}}} // giada::c::recorder::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <cassert>
#include <FL/Fl.H>
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../gui/dialogs/sampleEditor.h"
-#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/warnings.h"
#include "../gui/elems/basics/button.h"
#include "../gui/elems/sampleEditor/waveTools.h"
#include "../gui/elems/sampleEditor/volumeTool.h"
namespace giada {
-namespace c {
+namespace c {
namespace sampleEditor
{
namespace
{
- /* m_waveBuffer
+ /* waveBuffer
A Wave used during cut/copy/paste operations. */
- Wave* m_waveBuffer = nullptr;
+ std::unique_ptr<Wave> waveBuffer_;
}; // {anonymous}
gdSampleEditor* getSampleEditorWindow()
{
- gdSampleEditor* se = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* se = static_cast<gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
assert(se != nullptr);
return se;
}
void copy(m::SampleChannel* ch, int a, int b)
{
- if (m_waveBuffer != nullptr)
- delete m_waveBuffer;
- m::waveManager::createFromWave(ch->wave, a, b, &m_waveBuffer);
+ waveBuffer_ = m::waveManager::createFromWave(ch->wave.get(), a, b);
}
return;
}
- m::wfx::paste(*m_waveBuffer, *ch->wave, a);
+ m::wfx::paste(*waveBuffer_.get(), *ch->wave.get(), a);
/* Shift begin/end points to keep the previous position. */
- int delta = m_waveBuffer->getSize();
+ int delta = waveBuffer_->getSize();
if (a < ch->getBegin() && a < ch->getEnd())
setBeginEnd(ch, ch->getBegin() + delta, ch->getEnd() + delta);
else
m::SampleChannel* newCh = static_cast<m::SampleChannel*>(c::channel::addChannel(
ch->guiChannel->getColumnIndex(), ChannelType::SAMPLE, G_GUI_CHANNEL_H_1));
- Wave* wave = nullptr;
- m::waveManager::createFromWave(ch->wave, a, b, &wave);
-
- newCh->pushWave(wave);
+ newCh->pushWave(m::waveManager::createFromWave(ch->wave.get(), a, b));
newCh->guiChannel->update();
}
bool isWaveBufferFull()
{
- return m_waveBuffer != nullptr;
+ return waveBuffer_ != nullptr;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../core/mixerHandler.h"
#include "../core/channel.h"
#include "../core/recorderHandler.h"
+#include "../core/pluginManager.h"
#include "../core/pluginHost.h"
#include "../core/plugin.h"
#include "../core/conf.h"
#include "../gui/elems/basics/progress.h"
#include "../gui/elems/mainWindow/keyboard/column.h"
#include "../gui/elems/mainWindow/keyboard/keyboard.h"
-#include "../gui/dialogs/gd_mainWindow.h"
-#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/mainWindow.h"
+#include "../gui/dialogs/warnings.h"
#include "../gui/dialogs/browser/browserSave.h"
#include "../gui/dialogs/browser/browserLoad.h"
#include "main.h"
#include "storage.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
using std::string;
using std::vector;
-using namespace giada;
+namespace giada {
+namespace c {
+namespace storage
+{
+namespace
+{
#ifdef WITH_VST
-static void glue_fillPatchGlobalsPlugins__(vector <m::Plugin*>* host, vector<m::patch::plugin_t>* patch)
+void fillPatchGlobalsPlugins_(vector<m::Plugin*> stack, vector<m::patch::plugin_t>& patch)
{
using namespace giada::m;
- for (unsigned i=0; i<host->size(); i++) {
- Plugin *pl = host->at(i);
+ for (const Plugin* plugin : stack) {
patch::plugin_t ppl;
- ppl.path = pl->getUniqueId();
- ppl.bypass = pl->isBypassed();
- int numParams = pl->getNumParameters();
- for (int k=0; k<numParams; k++)
- ppl.params.push_back(pl->getParameter(k));
- patch->push_back(ppl);
+ ppl.path = plugin->getUniqueId();
+ ppl.bypass = plugin->isBypassed();
+ for (int k=0; k<plugin->getNumParameters(); k++)
+ ppl.params.push_back(plugin->getParameter(k));
+ patch.push_back(ppl);
}
}
/* -------------------------------------------------------------------------- */
-static void glue_fillPatchColumns__()
+void fillPatchColumns_()
{
using namespace giada::m;
/* -------------------------------------------------------------------------- */
-static void glue_fillPatchChannels__(bool isProject)
+void fillPatchChannels_(bool isProject)
{
using namespace giada::m;
- for (unsigned i=0; i<mixer::channels.size(); i++) {
+ for (unsigned i=0; i<mixer::channels.size(); i++)
mixer::channels.at(i)->writePatch(i, isProject);
- }
}
/* -------------------------------------------------------------------------- */
-static void glue_fillPatchGlobals__(const string &name)
+void fillPatchGlobals_(const string& name)
{
using namespace giada::m;
patch::bars = clock::getBars();
patch::beats = clock::getBeats();
patch::quantize = clock::getQuantize();
- patch::masterVolIn = mixer::inVol;
- patch::masterVolOut = mixer::outVol;
- patch::metronome = mixer::metronome;
+ patch::masterVolIn = mixer::inVol.load();
+ patch::masterVolOut = mixer::outVol.load();
+ patch::metronome = mixer::isMetronomeOn();
#ifdef WITH_VST
- glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_IN),
- &patch::masterInPlugins);
- glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_OUT),
- &patch::masterOutPlugins);
+ fillPatchGlobalsPlugins_(pluginHost::getStack(pluginHost::StackType::MASTER_IN),
+ patch::masterInPlugins);
+ fillPatchGlobalsPlugins_(pluginHost::getStack(pluginHost::StackType::MASTER_OUT),
+ patch::masterOutPlugins);
#endif
}
/* -------------------------------------------------------------------------- */
-static bool glue_savePatch__(const string &fullPath, const string &name,
- bool isProject)
+bool savePatch_(const string& fullPath, const string& name, bool isProject)
{
using namespace giada::m;
patch::init();
- glue_fillPatchGlobals__(name);
- glue_fillPatchChannels__(isProject);
- glue_fillPatchColumns__();
+ fillPatchGlobals_(name);
+ fillPatchChannels_(isProject);
+ fillPatchColumns_();
if (patch::write(fullPath)) {
- gu_updateMainWinLabel(name);
- gu_log("[glue_savePatch] patch saved as %s\n", fullPath.c_str());
+ u::gui::updateMainWinLabel(name);
+ gu_log("[savePatch] patch saved as %s\n", fullPath.c_str());
return true;
}
return false;
/* -------------------------------------------------------------------------- */
-static string glue_makeSamplePath__(const string& base, const Wave* w, int k)
+string makeSamplePath_(const string& base, const Wave& w, int k)
{
- return base + G_SLASH + w->getBasename(false) + "-" + gu_iToString(k) + "." + w->getExtension();
+ return base + G_SLASH + w.getBasename(false) + "-" + u::string::iToString(k) + "." + w.getExtension();
}
-static string glue_makeUniqueSamplePath__(const string& base, const m::SampleChannel* ch)
+string makeUniqueSamplePath_(const string& base, const m::SampleChannel* ch)
{
using namespace giada::m;
return path;
int k = 0;
- path = glue_makeSamplePath__(base, ch->wave, k);
+ path = makeSamplePath_(base, *ch->wave.get(), k);
while (!mh::uniqueSamplePath(ch, path))
- path = glue_makeSamplePath__(base, ch->wave, k++);
+ path = makeSamplePath_(base, *ch->wave.get(), k++);
return path;
}
+} // {anonymous}
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
-void glue_savePatch(void* data)
+void savePatch(void* data)
{
gdBrowserSave* browser = (gdBrowserSave*) data;
string name = gu_stripExt(browser->getName());
if (!gdConfirmWin("Warning", "File exists: overwrite?"))
return;
- if (glue_savePatch__(fullPath, name, false)) { // false == not a project
+ if (savePatch_(fullPath, name, false)) { // false == not a project
m::conf::patchPath = gu_dirname(fullPath);
browser->do_callback();
}
/* -------------------------------------------------------------------------- */
-void glue_loadPatch(void* data)
+void loadPatch(void* data)
{
using namespace giada::m;
/* Close all other windows. This prevents problems if plugin windows are
open. */
- gu_closeAllSubwindows();
+ u::gui::closeAllSubwindows();
/* Reset the system. False(1): don't update the gui right now. False(2): do
not create empty columns. */
- glue_resetToInitState(false, false);
+ c::main::resetToInitState(false, false);
browser->setStatusBar(0.1f);
/* Refresh GUI. */
- gu_updateControls();
- gu_updateMainWinLabel(patch::name);
+ u::gui::updateControls();
+ u::gui::updateMainWinLabel(patch::name);
browser->setStatusBar(0.1f);
#ifdef WITH_VST
- if (pluginHost::hasMissingPlugins())
+ if (pluginManager::hasMissingPlugins())
gdAlert("Some plugins were not loaded successfully.\nCheck the plugin browser to know more.");
#endif
/* -------------------------------------------------------------------------- */
-void glue_saveProject(void* data)
+void saveProject(void* data)
{
using namespace giada::m;
return;
if (!gu_dirExists(fullPath) && !gu_mkdir(fullPath)) {
- gu_log("[glue_saveProject] Unable to make project directory!\n");
+ gu_log("[saveProject] Unable to make project directory!\n");
return;
}
- gu_log("[glue_saveProject] Project dir created: %s\n", fullPath.c_str());
+ gu_log("[saveProject] Project dir created: %s\n", fullPath.c_str());
/* Copy all samples inside the folder. Takes and logical ones are saved via
- glue_saveSample(). Update the new sample path: everything now comes from the
+ saveSample(). Update the new sample path: everything now comes from the
project folder (folderPath). Also make sure the file path is unique inside the
project folder.*/
if (sch->wave == nullptr)
continue;
- sch->wave->setPath(glue_makeUniqueSamplePath__(fullPath, sch));
+ sch->wave->setPath(makeUniqueSamplePath_(fullPath, sch));
- gu_log("[glue_saveProject] Save file to %s\n", sch->wave->getPath().c_str());
+ gu_log("[saveProject] Save file to %s\n", sch->wave->getPath().c_str());
- waveManager::save(sch->wave, sch->wave->getPath()); // TODO - error checking
+ waveManager::save(sch->wave.get(), sch->wave->getPath()); // TODO - error checking
}
string gptcPath = fullPath + G_SLASH + name + ".gptc";
- if (glue_savePatch__(gptcPath, name, true)) // true == it's a project
+ if (savePatch_(gptcPath, name, true)) // true == it's a project
browser->do_callback();
else
gdAlert("Unable to save the project!");
/* -------------------------------------------------------------------------- */
-void glue_loadSample(void* data)
+void loadSample(void* data)
{
gdBrowserLoad* browser = (gdBrowserLoad*) data;
string fullPath = browser->getSelectedItem();
/* -------------------------------------------------------------------------- */
-void glue_saveSample(void* data)
+void saveSample(void* data)
{
using namespace giada::m;
SampleChannel* ch = static_cast<SampleChannel*>(browser->getChannel());
- if (waveManager::save(ch->wave, filePath)) {
- gu_log("[glue_saveSample] sample saved to %s\n", filePath.c_str());
+ if (waveManager::save(ch->wave.get(), filePath)) {
+ gu_log("[saveSample] sample saved to %s\n", filePath.c_str());
conf::samplePath = gu_dirname(filePath);
browser->do_callback();
}
else
gdAlert("Unable to save this sample!");
}
+
+}}} // giada::c::storage::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#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);
-
+namespace giada {
+namespace c {
+namespace storage
+{
+void loadPatch (void* data);
+void savePatch (void* data);
+void saveProject(void* data);
+void saveSample (void* data);
+void loadSample (void* data);
+}}} // giada::c::storage::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/Fl.H>
#include "../gui/elems/mainWindow/mainTransport.h"
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../core/clock.h"
#include "../core/conf.h"
#include "../core/const.h"
#include "../core/mixerHandler.h"
#include "../core/mixer.h"
#include "../core/recorder.h"
+#include "../core/recManager.h"
#include "transport.h"
void startSeq(bool gui)
{
- clock::start();
+ switch (clock::getStatus()) {
+ case ClockStatus::STOPPED:
+ clock::setStatus(ClockStatus::RUNNING);
+ break;
+ case ClockStatus::WAITING:
+ clock::setStatus(ClockStatus::RUNNING);
+ m::recManager::stopActionRec();
+ G_MainWin->mainTransport->setRecTriggerModeActive(true);
+ G_MainWin->mainTransport->updateRecAction(0);
+ G_MainWin->mainTransport->updateRecInput(0);
+ break;
+ default:
+ break;
+ }
#ifdef __linux__
kernelAudio::jackStart();
Fl::lock();
G_MainWin->mainTransport->updatePlay(1);
Fl::unlock();
- }
+ }
}
/* -------------------------------------------------------------------------- */
-void startStopMetronome(bool gui)
+void toggleMetronome(bool gui)
{
- mixer::metronome = !mixer::metronome;
+ mixer::toggleMetronome();
if (!gui) {
Fl::lock();
- G_MainWin->mainTransport->updateMetronome(mixer::metronome);
+ G_MainWin->mainTransport->updateMetronome(mixer::isMetronomeOn());
Fl::unlock();
}
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
void startSeq(bool gui=true);
void stopSeq(bool gui=true);
void rewindSeq(bool gui=true, bool notifyJack=true);
-void startStopMetronome(bool gui=true);
+void toggleMetronome(bool gui=true);
}}} // giada::c::transport::
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "about.h"
-using std::string;
-using namespace giada::m;
-using namespace giada::u;
+using namespace giada;
gdAbout::gdAbout()
: gdWindow(340, 350, "About Giada")
#endif
{
- if (conf::aboutX)
- resize(conf::aboutX, conf::aboutY, w(), h());
+ if (m::conf::aboutX)
+ resize(m::conf::aboutX, m::conf::aboutY, w(), h());
set_modal();
logo->image(new Fl_Pixmap(giada_logo_xpm));
text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
- string message = gu_format(
- "Version " G_VERSION_STR " (" BUILD_DATE ")\n\n"
+ std::string message = u::string::format(
+ "Version %s (" BUILD_DATE ")\n\n"
"Developed by Monocasual Laboratories\n"
"Based on FLTK (%d.%d.%d), RtAudio (%s),\n"
"RtMidi (%s), Libsamplerate, Jansson (%s),\n"
"Public License (GPL v3)\n\n"
"News, infos, contacts and documentation:\n"
"www.giadamusic.com",
- FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION,
- ver::getRtAudioVersion().c_str(),
- ver::getRtMidiVersion().c_str(),
- JANSSON_VERSION, ver::getLibsndfileVersion().c_str()
+ G_VERSION_STR, FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION,
+ u::ver::getRtAudioVersion().c_str(),
+ u::ver::getRtMidiVersion().c_str(),
+ JANSSON_VERSION, u::ver::getLibsndfileVersion().c_str()
#ifdef WITH_VST
, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER
#endif
#endif
close->callback(cb_close, (void*)this);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
setId(WID_ABOUT);
show();
}
gdAbout::~gdAbout()
{
- conf::aboutX = x();
- conf::aboutY = y();
+ m::conf::aboutX = x();
+ m::conf::aboutY = y();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "baseActionEditor.h"
-using std::string;
-
-
namespace giada {
namespace v
{
/* -------------------------------------------------------------------------- */
-void gdBaseActionEditor::cb_zoomIn(Fl_Widget *w, void *p) { ((gdBaseActionEditor*)p)->zoomIn(); }
-void gdBaseActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdBaseActionEditor*)p)->zoomOut(); }
+void gdBaseActionEditor::cb_zoomIn(Fl_Widget* w, void* p) { ((gdBaseActionEditor*)p)->zoomIn(); }
+void gdBaseActionEditor::cb_zoomOut(Fl_Widget* w, void* p) { ((gdBaseActionEditor*)p)->zoomOut(); }
/* -------------------------------------------------------------------------- */
void gdBaseActionEditor::prepareWindow()
{
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
- string l = "Action Editor";
+ std::string l = "Action Editor";
if (ch->name != "") l += " - " + ch->name;
copy_label(l.c_str());
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace m
{
class Channel;
-class Action;
+struct Action;
}
namespace v
{
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../elems/basics/button.h"
#include "../elems/basics/check.h"
#include "beatsInput.h"
-#include "gd_mainWindow.h"
+#include "mainWindow.h"
extern gdMainWindow* mainWin;
-using namespace giada::m;
+using namespace giada;
gdBeatsInput::gdBeatsInput()
: gdWindow(180, 36, "Beats")
{
- if (conf::beatsX)
- resize(conf::beatsX, conf::beatsY, w(), h());
+ if (m::conf::beatsX)
+ resize(m::conf::beatsX, m::conf::beatsY, w(), h());
set_modal();
end();
beats->maximum_size(2);
- beats->value(gu_iToString(clock::getBeats()).c_str());
+ beats->value(u::string::iToString(m::clock::getBeats()).c_str());
beats->type(FL_INT_INPUT);
bars->maximum_size(2);
- bars->value(gu_iToString(clock::getBars()).c_str());
+ bars->value(u::string::iToString(m::clock::getBars()).c_str());
bars->type(FL_INT_INPUT);
ok->shortcut(FL_Enter);
ok->callback(cb_update, (void*)this);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
setId(WID_BEATS);
show();
}
gdBeatsInput::~gdBeatsInput()
{
- conf::beatsX = x();
- conf::beatsY = y();
+ m::conf::beatsX = x();
+ m::conf::beatsY = y();
}
{
if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
return;
- glue_setBeats(atoi(beats->value()), atoi(bars->value()));
+ c::main::setBeats(atoi(beats->value()), atoi(bars->value()));
do_callback();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../elems/basics/button.h"
#include "../elems/basics/input.h"
#include "bpmInput.h"
-#include "gd_mainWindow.h"
+#include "mainWindow.h"
-extern gdMainWindow *mainWin;
+extern gdMainWindow* mainWin;
using std::vector;
using std::string;
-using namespace giada::m;
+using namespace giada;
gdBpmInput::gdBpmInput(const char* label)
: gdWindow(144, 36, "Bpm")
{
- if (conf::bpmX)
- resize(conf::bpmX, conf::bpmY, w(), h());
+ if (m::conf::bpmX)
+ resize(m::conf::bpmX, m::conf::bpmY, w(), h());
set_modal();
input_a = new geInput(8, 8, 30, G_GUI_UNIT);
input_b = new geInput(42, 8, 20, G_GUI_UNIT);
- ok = new geButton(66, 8, 70, G_GUI_UNIT, "Ok");
+ ok = new geButton(66, 8, 70, G_GUI_UNIT, "Ok");
end();
input_a->maximum_size(3);
input_a->type(FL_INT_INPUT);
- input_a->value(gu_fToString(clock::getBpm(), 0).c_str());
+ input_a->value(u::string::fToString(m::clock::getBpm(), 0).c_str());
/* Use the decimal value from the string label. */
- vector<string> tokens;
- gu_split(label, ".", &tokens);
+ vector<string> tokens = u::string::split(label, ".");
+
input_b->maximum_size(1);
input_b->type(FL_INT_INPUT);
input_b->value(tokens[1].c_str());
ok->shortcut(FL_Enter);
ok->callback(cb_update, (void*)this);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
setId(WID_BPM);
show();
}
gdBpmInput::~gdBpmInput()
{
- conf::bpmX = x();
- conf::bpmY = y();
+ m::conf::bpmX = x();
+ m::conf::bpmY = y();
}
{
if (strcmp(input_a->value(), "") == 0)
return;
- glue_setBpm(input_a->value(), input_b->value());
+ c::main::setBpm(input_a->value(), input_b->value());
do_callback();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
+using namespace giada;
using namespace giada::m;
resizable(browser);
size_range(320, 200);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
m_cancel->callback(cb_cancel, (void*)this);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
setId(WID_SAMPLE_NAME);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 <FL/Fl_Tabs.H>
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../utils/gui.h"
+#include "../elems/basics/boxtypes.h"
+#include "../elems/basics/button.h"
+#include "../elems/config/tabMisc.h"
+#include "../elems/config/tabMidi.h"
+#include "../elems/config/tabAudio.h"
+#include "../elems/config/tabBehaviors.h"
+#include "../elems/config/tabPlugins.h"
+#include "config.h"
+
+
+using namespace giada;
+using namespace giada::m;
+
+
+gdConfig::gdConfig(int w, int h) : gdWindow(w, h, "Configuration")
+{
+ if (conf::configX)
+ resize(conf::configX, conf::configY, this->w(), this->h());
+
+ Fl_Tabs* tabs = new Fl_Tabs(8, 8, w-16, h-44);
+ tabs->box(G_CUSTOM_BORDER_BOX);
+ tabs->labelcolor(G_COLOR_LIGHT_2);
+ tabs->begin();
+
+ tabAudio = new geTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+ tabMidi = new geTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+ tabBehaviors = new geTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+ tabMisc = new geTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+#ifdef WITH_VST
+ tabPlugins = new geTabPlugins(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+#endif
+
+ tabs->end();
+
+ save = new geButton (w-88, h-28, 80, 20, "Save");
+ cancel = new geButton (w-176, h-28, 80, 20, "Cancel");
+
+ end();
+
+ save->callback(cb_save_config, (void*)this);
+ cancel->callback(cb_cancel, (void*)this);
+
+ u::gui::setFavicon(this);
+ setId(WID_CONFIG);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdConfig::~gdConfig()
+{
+ conf::configX = x();
+ conf::configY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::cb_save_config(Fl_Widget* w, void* p) { ((gdConfig*)p)->cb_save_config(); }
+void gdConfig::cb_cancel (Fl_Widget* w, void* p) { ((gdConfig*)p)->cb_cancel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::cb_save_config()
+{
+ tabAudio->save();
+ tabBehaviors->save();
+ tabMidi->save();
+ tabMisc->save();
+#ifdef WITH_VST
+ tabPlugins->save();
+#endif
+ do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdConfig::cb_cancel()
+{
+ do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef WITH_VST
+
+void gdConfig::refreshVstPath()
+{
+ tabPlugins->refreshVstPath();
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_CONFIG_H
+#define GD_CONFIG_H
+
+
+#include "window.h"
+
+
+class geTabAudio;
+class geTabBehaviors;
+class geTabMidi;
+class geTabMisc;
+#ifdef WITH_VST
+class geTabPlugins;
+#endif
+class geButton;
+class geChoice;
+class geCheck;
+class geInput;
+class geRadio;
+class geBox;
+
+
+class gdConfig : public gdWindow
+{
+private:
+
+ static void cb_save_config(Fl_Widget* w, void* p);
+ static void cb_cancel(Fl_Widget* w, void* p);
+ void cb_save_config();
+ void cb_cancel();
+
+public:
+
+ geTabAudio* tabAudio;
+ geTabBehaviors* tabBehaviors;
+ geTabMidi* tabMidi;
+ geTabMisc* tabMisc;
+#ifdef WITH_VST
+ geTabPlugins* tabPlugins;
+#endif
+ geButton* save;
+ geButton* cancel;
+
+ gdConfig(int w, int h);
+ ~gdConfig();
+
+#ifdef WITH_VST
+ void refreshVstPath();
+#endif
+};
+
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 <FL/fl_draw.H>
+#include "../../core/kernelAudio.h"
+#include "../../utils/gui.h"
+#include "../../utils/string.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/box.h"
+#include "window.h"
+#include "devInfo.h"
+
+
+using std::string;
+using namespace giada;
+
+
+gdDevInfo::gdDevInfo(unsigned dev)
+ : Fl_Window(340, 300, "Device information")
+{
+ set_modal();
+
+ text = new geBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
+ close = new geButton(252, h()-28, 80, 20, "Close");
+ end();
+
+ string body = "";
+ int lines = 7;
+
+ body = "Device name: " + m::kernelAudio::getDeviceName(dev) + "\n";
+ body += "Total output(s): " + u::string::iToString(m::kernelAudio::getMaxOutChans(dev)) + "\n";
+ body += "Total intput(s): " + u::string::iToString(m::kernelAudio::getMaxInChans(dev)) + "\n";
+ body += "Duplex channel(s): " + u::string::iToString(m::kernelAudio::getDuplexChans(dev)) + "\n";
+ body += "Default output: " + string(m::kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n";
+ body += "Default input: " + string(m::kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n";
+
+ int totalFreq = m::kernelAudio::getTotalFreqs(dev);
+ body += "Supported frequencies: " + u::string::iToString(totalFreq);
+
+ for (int i=0; i<totalFreq; i++) {
+ if (i % 6 == 0) {
+ body += "\n "; // add new line each 6 printed freqs AND on the first line (i % 0 != 0)
+ lines++;
+ }
+ body += u::string::iToString(m::kernelAudio::getFreq(dev, i)) + " ";
+ }
+
+ text->copy_label(body.c_str());
+
+ /* resize the window to fit the content. fl_height() returns the height
+ * of a line. fl_height() * total lines + margins + button size */
+
+ resize(x(), y(), w(), (lines * fl_height()) + 8 + 8 + 8 + 20);
+ close->position(close->x(), (lines * fl_height()) + 8 + 8);
+
+ close->callback(__cb_window_closer, (void*)this);
+ u::gui::setFavicon(this);
+ show();
+}
+
+
+gdDevInfo::~gdDevInfo() {}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_DEV_INFO_H
+#define GD_DEV_INFO_H
+
+
+#include <FL/Fl_Window.H>
+
+
+class geBox;
+class geButton;
+
+
+class gdDevInfo : public Fl_Window
+{
+private:
+
+ geBox *text;
+ geButton *close;
+
+public:
+
+ gdDevInfo(unsigned dev);
+ ~gdDevInfo();
+};
+
+#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 <FL/Fl_Tabs.H>
-#include "../../core/conf.h"
-#include "../../core/const.h"
-#include "../../utils/gui.h"
-#include "../elems/basics/boxtypes.h"
-#include "../elems/basics/button.h"
-#include "../elems/config/tabMisc.h"
-#include "../elems/config/tabMidi.h"
-#include "../elems/config/tabAudio.h"
-#include "../elems/config/tabBehaviors.h"
-#include "../elems/config/tabPlugins.h"
-#include "gd_config.h"
-
-
-using namespace giada::m;
-
-
-gdConfig::gdConfig(int w, int h) : gdWindow(w, h, "Configuration")
-{
- if (conf::configX)
- resize(conf::configX, conf::configY, this->w(), this->h());
-
- Fl_Tabs* tabs = new Fl_Tabs(8, 8, w-16, h-44);
- tabs->box(G_CUSTOM_BORDER_BOX);
- tabs->labelcolor(G_COLOR_LIGHT_2);
- tabs->begin();
-
- tabAudio = new geTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
- tabMidi = new geTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
- tabBehaviors = new geTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
- tabMisc = new geTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-#ifdef WITH_VST
- tabPlugins = new geTabPlugins(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-#endif
-
- tabs->end();
-
- save = new geButton (w-88, h-28, 80, 20, "Save");
- cancel = new geButton (w-176, h-28, 80, 20, "Cancel");
-
- end();
-
- save->callback(cb_save_config, (void*)this);
- cancel->callback(cb_cancel, (void*)this);
-
- gu_setFavicon(this);
- setId(WID_CONFIG);
- show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdConfig::~gdConfig()
-{
- conf::configX = x();
- conf::configY = y();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::cb_save_config(Fl_Widget* w, void* p) { ((gdConfig*)p)->cb_save_config(); }
-void gdConfig::cb_cancel (Fl_Widget* w, void* p) { ((gdConfig*)p)->cb_cancel(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::cb_save_config()
-{
- tabAudio->save();
- tabBehaviors->save();
- tabMidi->save();
- tabMisc->save();
-#ifdef WITH_VST
- tabPlugins->save();
-#endif
- do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdConfig::cb_cancel()
-{
- do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef WITH_VST
-
-void gdConfig::refreshVstPath()
-{
- tabPlugins->refreshVstPath();
-}
-
-#endif
\ No newline at end of file
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 GD_CONFIG_H
-#define GD_CONFIG_H
-
-
-#include "window.h"
-
-
-class geTabAudio;
-class geTabBehaviors;
-class geTabMidi;
-class geTabMisc;
-#ifdef WITH_VST
-class geTabPlugins;
-#endif
-class geButton;
-class geChoice;
-class geCheck;
-class geInput;
-class geRadio;
-class geBox;
-
-
-class gdConfig : public gdWindow
-{
-private:
-
- static void cb_save_config(Fl_Widget* w, void* p);
- static void cb_cancel(Fl_Widget* w, void* p);
- void cb_save_config();
- void cb_cancel();
-
-public:
-
- geTabAudio* tabAudio;
- geTabBehaviors* tabBehaviors;
- geTabMidi* tabMidi;
- geTabMisc* tabMisc;
-#ifdef WITH_VST
- geTabPlugins* tabPlugins;
-#endif
- geButton* save;
- geButton* cancel;
-
- gdConfig(int w, int h);
- ~gdConfig();
-
-#ifdef WITH_VST
- void refreshVstPath();
-#endif
-};
-
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 <FL/fl_draw.H>
-#include "../../core/kernelAudio.h"
-#include "../../utils/gui.h"
-#include "../../utils/string.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/box.h"
-#include "window.h"
-#include "gd_devInfo.h"
-
-
-using std::string;
-using namespace giada::m;
-
-
-gdDevInfo::gdDevInfo(unsigned dev)
- : Fl_Window(340, 300, "Device information")
-{
- set_modal();
-
- text = new geBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
- close = new geButton(252, h()-28, 80, 20, "Close");
- end();
-
- string body = "";
- int lines = 7;
-
- body = "Device name: " + kernelAudio::getDeviceName(dev) + "\n";
- body += "Total output(s): " + gu_iToString(kernelAudio::getMaxOutChans(dev)) + "\n";
- body += "Total intput(s): " + gu_iToString(kernelAudio::getMaxInChans(dev)) + "\n";
- body += "Duplex channel(s): " + gu_iToString(kernelAudio::getDuplexChans(dev)) + "\n";
- body += "Default output: " + string(kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n";
- body += "Default input: " + string(kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n";
-
- int totalFreq = kernelAudio::getTotalFreqs(dev);
- body += "Supported frequencies: " + gu_iToString(totalFreq);
-
- for (int i=0; i<totalFreq; i++) {
- if (i % 6 == 0) {
- body += "\n "; // add new line each 6 printed freqs AND on the first line (i % 0 != 0)
- lines++;
- }
- body += gu_iToString( kernelAudio::getFreq(dev, i)) + " ";
- }
-
- text->copy_label(body.c_str());
-
- /* resize the window to fit the content. fl_height() returns the height
- * of a line. fl_height() * total lines + margins + button size */
-
- resize(x(), y(), w(), (lines * fl_height()) + 8 + 8 + 8 + 20);
- close->position(close->x(), (lines * fl_height()) + 8 + 8);
-
- close->callback(__cb_window_closer, (void*)this);
- gu_setFavicon(this);
- show();
-}
-
-
-gdDevInfo::~gdDevInfo() {}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 GD_DEV_INFO_H
-#define GD_DEV_INFO_H
-
-
-#include <FL/Fl_Window.H>
-
-
-class geBox;
-class geButton;
-
-
-class gdDevInfo : public Fl_Window
-{
-private:
-
- geBox *text;
- geButton *close;
-
-public:
-
- gdDevInfo(unsigned dev);
- ~gdDevInfo();
-};
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 "../../utils/gui.h"
-#include "../../utils/string.h"
-#include "../../core/conf.h"
-#include "../../core/channel.h"
-#include "../../core/sampleChannel.h"
-#include "../../core/midiChannel.h"
-#include "../../utils/log.h"
-#include "../elems/basics/box.h"
-#include "../elems/mainWindow/keyboard/keyboard.h"
-#include "../elems/mainWindow/keyboard/channel.h"
-#include "../elems/mainWindow/keyboard/channelButton.h"
-#include "gd_keyGrabber.h"
-#include "gd_config.h"
-#include "gd_mainWindow.h"
-
-
-extern gdMainWindow *mainWin;
-
-
-using std::string;
-using namespace giada;
-
-
-gdKeyGrabber::gdKeyGrabber(m::Channel* ch)
- : gdWindow(300, 126, "Key configuration"), ch(ch)
-{
- set_modal();
- text = new geBox(8, 8, 284, 80, "");
- clear = new geButton(w()-88, text->y()+text->h()+8, 80, 20, "Clear");
- cancel = new geButton(clear->x()-88, clear->y(), 80, 20, "Close");
- end();
-
- clear->callback(cb_clear, (void*)this);
- cancel->callback(cb_cancel, (void*)this);
-
- updateText(ch->key);
-
- gu_setFavicon(this);
- show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-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()
-{
- do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::cb_clear()
-{
- updateText(0);
- setButtonLabel(0);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::setButtonLabel(int key)
-{
- ch->guiChannel->mainButton->setKey(key);
- ch->key = key;
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdKeyGrabber::updateText(int key)
-{
- string tmp = "Press a key.\n\nCurrent binding: ";
- if (key != 0)
- tmp += static_cast<char>(key);
- else
- tmp += "[none]";
- text->copy_label(tmp.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int gdKeyGrabber::handle(int e)
-{
- int ret = Fl_Group::handle(e);
- switch(e) {
- case FL_KEYUP: {
- int x = Fl::event_key();
- if (strlen(Fl::event_text()) != 0
- && x != FL_BackSpace
- && x != FL_Enter
- && x != FL_Delete
- && x != FL_Tab
- && x != FL_End
- && x != ' ')
- {
- gu_log("set key '%c' (%d) for channel %d\n", x, x, ch->index);
- setButtonLabel(x);
- updateText(x);
- break;
- }
- else
- gu_log("invalid key\n");
- }
- }
- return(ret);
-}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 GD_KEYGRABBER_H
-#define GD_KEYGRABBER_H
-
-
-#include <FL/Fl.H>
-#include "window.h"
-
-
-class geBox;
-class geButton;
-
-
-class gdKeyGrabber : public gdWindow
-{
-private:
-
- giada::m::Channel* ch;
-
- geBox* text;
- geButton* clear;
- geButton* 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(giada::m::Channel* ch);
- int handle(int e);
-};
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 <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 "../elems/mainWindow/mainIO.h"
-#include "../elems/mainWindow/mainMenu.h"
-#include "../elems/mainWindow/mainTimer.h"
-#include "../elems/mainWindow/mainTransport.h"
-#include "../elems/mainWindow/beatMeter.h"
-#include "../elems/mainWindow/keyboard/keyboard.h"
-#include "gd_warnings.h"
-#include "gd_mainWindow.h"
-
-
-extern gdMainWindow* G_MainWin;
-
-
-using namespace giada;
-
-
-gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** argv)
- : gdWindow(W, H, title)
-{
- Fl::visible_focus(0);
-
- Fl::background(25, 25, 25);
-
- Fl::set_boxtype(G_CUSTOM_BORDER_BOX, g_customBorderBox, 1, 1, 2, 2);
- 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);
-
- size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
-
- mainMenu = new geMainMenu(8, -1);
- mainIO = new geMainIO(412, 8);
- mainTransport = new geMainTransport(8, 39);
- mainTimer = new geMainTimer(628, 44);
- beatMeter = new geBeatMeter(100, 83, 609, 20);
- keyboard = new geKeyboard(8, 122, w()-16, 380);
-
- /* zone 1 - menus, and I/O tools */
-
- Fl_Group* zone1 = new Fl_Group(8, 8, W-16, 20);
- zone1->add(mainMenu);
- zone1->resizable(new Fl_Box(300, 8, 80, 20));
- zone1->add(mainIO);
-
- /* zone 2 - mainTransport and timing tools */
-
- Fl_Group* zone2 = new Fl_Group(8, mainTransport->y(), W-16, mainTransport->h());
- zone2->add(mainTransport);
- zone2->resizable(new Fl_Box(mainTransport->x()+mainTransport->w()+4, zone2->y(), 80, 20));
- zone2->add(mainTimer);
-
- /* zone 3 - beat meter */
-
- Fl_Group* zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h());
- zone3->add(beatMeter);
-
- /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
- * a group by itself) */
-
- resizable(keyboard);
-
- add(zone1);
- add(zone2);
- add(zone3);
- add(keyboard);
- callback(cb_endprogram);
- gu_setFavicon(this);
-
- show(argc, argv);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMainWindow::cb_endprogram(Fl_Widget* v, void* p) { G_MainWin->cb_endprogram(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdMainWindow::cb_endprogram()
-{
- if (!gdConfirmWin("Warning", "Quit Giada: are you sure?"))
- return;
-
- m::conf::mainWindowX = x();
- m::conf::mainWindowY = y();
- m::conf::mainWindowW = w();
- m::conf::mainWindowH = h();
-
- hide();
- delete this;
-}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 GD_MAINWINDOW_H
-#define GD_MAINWINDOW_H
-
-
-#include "window.h"
-
-
-class Fl_Widget;
-class geKeyboard;
-class geBeatMeter;
-class geMainMenu;
-class geMainIO;
-class geMainTimer;
-class geMainTransport;
-
-
-class gdMainWindow : public gdWindow
-{
-private:
-
- static void cb_endprogram(Fl_Widget* v, void* p);
- inline void cb_endprogram();
-
-public:
-
- geKeyboard* keyboard;
- geBeatMeter* beatMeter;
- geMainMenu* mainMenu;
- geMainIO* mainIO;
- geMainTimer* mainTimer;
- geMainTransport* mainTransport;
-
- gdMainWindow(int w, int h, const char* title, int argc, char** argv);
-};
-
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "../../utils/gui.h"
-#include "../../core/const.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/box.h"
-#include "window.h"
-#include "gd_warnings.h"
-
-
-void gdAlert(const char *c)
-{
- Fl_Window *modal = new Fl_Window(
- (Fl::w() / 2) - 150,
- (Fl::h() / 2) - 47,
- 300, 90, "Alert");
- modal->set_modal();
- modal->begin();
- geBox *box = new geBox(10, 10, 280, 40, c);
- geButton *b = new geButton(210, 60, 80, 20, "Close");
- modal->end();
- box->labelsize(G_GUI_FONT_SIZE_BASE);
- b->callback(__cb_window_closer, (void *)modal);
- b->shortcut(FL_Enter);
- gu_setFavicon(modal);
- modal->show();
-}
-
-
-int gdConfirmWin(const char *title, const char *msg)
-{
- Fl_Window *win = new Fl_Window(
- (Fl::w() / 2) - 150,
- (Fl::h() / 2) - 47,
- 300, 90, title);
- win->set_modal();
- win->begin();
- new geBox(10, 10, 280, 40, msg);
- geButton *ok = new geButton(212, 62, 80, 20, "Ok");
- geButton *ko = new geButton(124, 62, 80, 20, "Cancel");
- win->end();
- ok->shortcut(FL_Enter);
- gu_setFavicon(win);
- win->show();
-
- /* no callbacks here. readqueue() check the event stack. */
-
- int r = 0;
- while (true) {
- Fl_Widget *o = Fl::readqueue();
- if (!o) Fl::wait();
- else if (o == ok) {r = 1; break;}
- else if (o == ko) {r = 0; break;}
- }
- //delete win;
- win->hide();
- return r;
-}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * 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 GD_WARNINGS_H
-#define GD_WARNINGS_H
-
-
-void gdAlert(const char *c);
-int gdConfirmWin(const char *title, const char *msg);
-
-
-#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 "../../utils/gui.h"
+#include "../../utils/string.h"
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../../core/sampleChannel.h"
+#include "../../core/midiChannel.h"
+#include "../../utils/log.h"
+#include "../elems/basics/box.h"
+#include "../elems/mainWindow/keyboard/keyboard.h"
+#include "../elems/mainWindow/keyboard/channel.h"
+#include "../elems/mainWindow/keyboard/channelButton.h"
+#include "keyGrabber.h"
+#include "config.h"
+#include "mainWindow.h"
+
+
+extern gdMainWindow *mainWin;
+
+
+using std::string;
+using namespace giada;
+
+
+gdKeyGrabber::gdKeyGrabber(m::Channel* ch)
+ : gdWindow(300, 126, "Key configuration"), ch(ch)
+{
+ set_modal();
+ text = new geBox(8, 8, 284, 80, "");
+ clear = new geButton(w()-88, text->y()+text->h()+8, 80, 20, "Clear");
+ cancel = new geButton(clear->x()-88, clear->y(), 80, 20, "Close");
+ end();
+
+ clear->callback(cb_clear, (void*)this);
+ cancel->callback(cb_cancel, (void*)this);
+
+ updateText(ch->key);
+
+ u::gui::setFavicon(this);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+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()
+{
+ do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::cb_clear()
+{
+ updateText(0);
+ setButtonLabel(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::setButtonLabel(int key)
+{
+ ch->guiChannel->mainButton->setKey(key);
+ ch->key = key;
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdKeyGrabber::updateText(int key)
+{
+ string tmp = "Press a key.\n\nCurrent binding: ";
+ if (key != 0)
+ tmp += static_cast<char>(key);
+ else
+ tmp += "[none]";
+ text->copy_label(tmp.c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gdKeyGrabber::handle(int e)
+{
+ int ret = Fl_Group::handle(e);
+ switch(e) {
+ case FL_KEYUP: {
+ int x = Fl::event_key();
+ if (strlen(Fl::event_text()) != 0
+ && x != FL_BackSpace
+ && x != FL_Enter
+ && x != FL_Delete
+ && x != FL_Tab
+ && x != FL_End
+ && x != ' ')
+ {
+ gu_log("set key '%c' (%d) for channel %d\n", x, x, ch->index);
+ setButtonLabel(x);
+ updateText(x);
+ break;
+ }
+ else
+ gu_log("invalid key\n");
+ }
+ }
+ return(ret);
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_KEYGRABBER_H
+#define GD_KEYGRABBER_H
+
+
+#include <FL/Fl.H>
+#include "window.h"
+
+
+class geBox;
+class geButton;
+
+
+class gdKeyGrabber : public gdWindow
+{
+private:
+
+ giada::m::Channel* ch;
+
+ geBox* text;
+ geButton* clear;
+ geButton* 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(giada::m::Channel* ch);
+ int handle(int e);
+};
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 <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 "../elems/mainWindow/mainIO.h"
+#include "../elems/mainWindow/mainMenu.h"
+#include "../elems/mainWindow/mainTimer.h"
+#include "../elems/mainWindow/mainTransport.h"
+#include "../elems/mainWindow/beatMeter.h"
+#include "../elems/mainWindow/keyboard/keyboard.h"
+#include "warnings.h"
+#include "mainWindow.h"
+
+
+extern gdMainWindow* G_MainWin;
+
+
+using namespace giada;
+
+
+gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** argv)
+ : gdWindow(W, H, title)
+{
+ Fl::visible_focus(0);
+
+ Fl::background(25, 25, 25);
+
+ Fl::set_boxtype(G_CUSTOM_BORDER_BOX, g_customBorderBox, 1, 1, 2, 2);
+ 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);
+
+ size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
+
+ mainMenu = new v::geMainMenu(8, -1);
+ mainIO = new v::geMainIO(412, 8);
+ mainTransport = new v::geMainTransport(8, 39);
+ mainTimer = new v::geMainTimer(598, 44);
+ beatMeter = new v::geBeatMeter(100, 83, 609, 20);
+ keyboard = new v::geKeyboard(8, 122, w()-16, 380);
+
+ /* zone 1 - menus, and I/O tools */
+
+ Fl_Group* zone1 = new Fl_Group(8, 8, W-16, 20);
+ zone1->add(mainMenu);
+ zone1->resizable(new Fl_Box(300, 8, 80, 20));
+ zone1->add(mainIO);
+
+ /* zone 2 - mainTransport and timing tools */
+
+ Fl_Group* zone2 = new Fl_Group(8, mainTransport->y(), W-16, mainTransport->h());
+ zone2->add(mainTransport);
+ zone2->resizable(new Fl_Box(mainTransport->x()+mainTransport->w()+4, zone2->y(), 80, 20));
+ zone2->add(mainTimer);
+
+ /* zone 3 - beat meter */
+
+ Fl_Group* zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h());
+ zone3->add(beatMeter);
+
+ /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
+ * a group by itself) */
+
+ resizable(keyboard);
+
+ add(zone1);
+ add(zone2);
+ add(zone3);
+ add(keyboard);
+ callback([](Fl_Widget* w, void* v) {
+ m::init::closeMainWindow();
+ });
+ u::gui::setFavicon(this);
+
+ show(argc, argv);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdMainWindow::~gdMainWindow()
+{
+ m::conf::mainWindowX = x();
+ m::conf::mainWindowY = y();
+ m::conf::mainWindowW = w();
+ m::conf::mainWindowH = h();
+}
\ No newline at end of file
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_MAINWINDOW_H
+#define GD_MAINWINDOW_H
+
+
+#include "window.h"
+
+
+class Fl_Widget;
+
+
+namespace giada {
+namespace v
+{
+class geKeyboard;
+class geMainIO;
+class geMainMenu;
+class geBeatMeter;
+class geMainTransport;
+class geMainTimer;
+}}
+
+
+class gdMainWindow : public gdWindow
+{
+public:
+
+ giada::v::geKeyboard* keyboard;
+ giada::v::geBeatMeter* beatMeter;
+ giada::v::geMainMenu* mainMenu;
+ giada::v::geMainIO* mainIO;
+ giada::v::geMainTimer* mainTimer;
+ giada::v::geMainTransport* mainTransport;
+
+ gdMainWindow(int w, int h, const char* title, int argc, char** argv);
+ ~gdMainWindow();
+};
+
+
+#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
conf::midiInputH, "MIDI Input Setup"),
ch(ch)
{
- string title = "MIDI Input Setup (channel " + gu_iToString(ch->index+1) + ")";
+ string title = "MIDI Input Setup (channel " + u::string::iToString(ch->index+1) + ")";
label(title.c_str());
size_range(G_DEFAULT_MIDI_INPUT_UI_W, G_DEFAULT_MIDI_INPUT_UI_H);
end();
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
set_modal();
show();
}
void gdMidiInputChannel::addPluginLearners()
{
- vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
- for (unsigned i=0; i<plugins->size(); i++) {
+ vector<Plugin*> plugins = pluginHost::getStack(pluginHost::StackType::CHANNEL, ch);
+
+ int i = 0;
+ for (Plugin* plugin : plugins) {
Fl_Pack* pack = new Fl_Pack(container->x() + ((i + 1) * (LEARNER_WIDTH + 8)),
container->y(), LEARNER_WIDTH, 200);
pack->spacing(4);
pack->begin();
- Plugin* plugin = plugins->at(i);
-
geBox* header = new geBox(0, 0, LEARNER_WIDTH, 20, plugin->getName().c_str());
header->box(FL_BORDER_BOX);
cb_learn, &plugin->midiInParams.at(k), ch);
pack->end();
+
+ i++;
}
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "midiInputMaster.h"
+using namespace giada;
using namespace giada::m;
channel->value(conf::midiInFilter -1 ? 0 : conf::midiInFilter + 1);
channel->callback(cb_setChannel, (void*)this);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
-using namespace giada::m;
+using namespace giada;
gdMidiOutputBase::gdMidiOutputBase(int w, int h)
void gdMidiOutputBase::stopMidiLearn(geMidiLearner *learner)
{
- midiDispatcher::stopMidiLearn();
+ m::midiDispatcher::stopMidiLearn();
learner->updateValue();
}
/* -------------------------------------------------------------------------- */
-void gdMidiOutputBase::__cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l)
+void gdMidiOutputBase::cb_learn(uint32_t* param, uint32_t msg, geMidiLearner* l)
{
*param = msg;
stopMidiLearn(l);
void gdMidiOutputBase::cb_learn(uint32_t msg, void *d)
{
- geMidiLearner::cbData_t *data = (geMidiLearner::cbData_t*) d;
- gdMidiOutputBase *window = (gdMidiOutputBase*) data->window;
- geMidiLearner *learner = data->learner;
- uint32_t *param = learner->param;
- window->__cb_learn(param, msg, learner);
+ geMidiLearner::cbData_t* data = (geMidiLearner::cbData_t*) d;
+ gdMidiOutputBase* window = (gdMidiOutputBase*) data->window;
+ geMidiLearner* learner = data->learner;
+ uint32_t* param = learner->param;
+ window->cb_learn(param, msg, learner);
}
/* -------------------------------------------------------------------------- */
-void gdMidiOutputBase::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputBase*)p)->__cb_close(); }
+void gdMidiOutputBase::cb_close(Fl_Widget* w, void* p) { ((gdMidiOutputBase*)p)->cb_close(); }
/* -------------------------------------------------------------------------- */
-void gdMidiOutputBase::__cb_close()
+void gdMidiOutputBase::cb_close()
{
do_callback();
}
/* -------------------------------------------------------------------------- */
-void gdMidiOutputBase::cb_enableLightning(Fl_Widget *w, void *p)
+void gdMidiOutputBase::cb_enableLightning(Fl_Widget* w, void* p)
{
- ((gdMidiOutputBase*)p)->__cb_enableLightning();
+ ((gdMidiOutputBase*)p)->cb_enableLightning();
}
/* -------------------------------------------------------------------------- */
-void gdMidiOutputBase::__cb_enableLightning() {}
+void gdMidiOutputBase::cb_enableLightning() {}
/* -------------------------------------------------------------------------- */
void gdMidiOutputBase::setTitle(int chanNum)
{
- string tmp = "MIDI Output Setup (channel " + gu_iToString(chanNum) + ")";
+ string tmp = "MIDI Output Setup (channel " + u::string::iToString(chanNum) + ")";
copy_label(tmp.c_str());
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
protected:
- geButton *close;
- geCheck *enableLightning;
+ geButton* close;
+ geCheck* enableLightning;
- void stopMidiLearn(geMidiLearner *l);
+ void stopMidiLearn(geMidiLearner* l);
/* cb_learn
* callback attached to kernelMidi to learn various actions. */
- static void cb_learn (uint32_t msg, void *data);
- inline void __cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l);
+ static void cb_learn(uint32_t msg, void* data);
+ void cb_learn(uint32_t* param, uint32_t msg, geMidiLearner* l);
/* cb_close
close current window. */
- static void cb_close (Fl_Widget *w, void *p);
- inline void __cb_close();
+ static void cb_close(Fl_Widget* w, void* p);
+ void cb_close();
/* cb_enableLightning
enable MIDI lightning output. */
- static void cb_enableLightning (Fl_Widget *w, void *p);
- inline void __cb_enableLightning();
+ static void cb_enableLightning (Fl_Widget* w, void* p);
+ void cb_enableLightning();
/* setTitle
* set window title. */
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
close->callback(cb_close, (void*)this);
set_modal();
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
enableLightning->callback(cb_enableLightning, (void*)this);
set_modal();
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../utils/gui.h"
#include "../../core/channel.h"
#include "../../core/conf.h"
+#include "../../core/pluginManager.h"
#include "../../core/pluginHost.h"
#include "../elems/plugin/pluginBrowser.h"
#include "../elems/basics/button.h"
#include "pluginChooser.h"
+using namespace giada;
using namespace giada::m;
using namespace giada::c;
-gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, int stackType, Channel* ch)
- : gdWindow(X, Y, W, H, "Available plugins"), ch(ch), stackType(stackType)
+gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, pluginHost::StackType t, Channel* ch)
+ : gdWindow(X, Y, W, H, "Available plugins"), ch(ch), stackType(t)
{
/* top area */
Fl_Group *group_top = new Fl_Group(8, 8, w()-16, 20);
cancelBtn->callback(cb_close, (void*) this);
resizable(browser);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
void gdPluginChooser::cb_sort()
{
- pluginHost::sortPlugins(sortMethod->value());
+ pluginManager::sortPlugins(static_cast<pluginManager::SortMethod>(sortMethod->value()));
browser->refresh();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
private:
giada::m::Channel* ch; // ch == nullptr ? masterOut
- int stackType;
+ giada::m::pluginHost::StackType stackType;
geChoice* sortMethod;
geButton* addBtn;
public:
- gdPluginChooser(int x, int y, int w, int h, int stackType, giada::m::Channel* ch=nullptr);
+ gdPluginChooser(int x, int y, int w, int h, giada::m::pluginHost::StackType t,
+ giada::m::Channel* ch=nullptr);
~gdPluginChooser();
};
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../elems/mainWindow/keyboard/channel.h"
#include "../elems/plugin/pluginElement.h"
#include "pluginChooser.h"
-#include "gd_mainWindow.h"
+#include "mainWindow.h"
#include "pluginList.h"
using namespace giada;
-gdPluginList::gdPluginList(int stackType, m::Channel* ch)
- : gdWindow(468, 204), ch(ch), stackType(stackType)
+gdPluginList::gdPluginList(m::pluginHost::StackType t, m::Channel* ch)
+ : gdWindow(468, 204), ch(ch), stackType(t)
{
using namespace giada::m;
/* TODO - awful stuff... we should subclass into gdPluginListChannel and
gdPluginListMaster */
- if (stackType == pluginHost::MASTER_OUT)
+ if (stackType == pluginHost::StackType::MASTER_OUT)
label("Master Out Plugins");
else
- if (stackType == pluginHost::MASTER_IN)
+ if (stackType == pluginHost::StackType::MASTER_IN)
label("Master In Plugins");
else {
- string l = "Channel " + gu_iToString(ch->index+1) + " Plugins";
+ string l = "Channel " + u::string::iToString(ch->index+1) + " Plugins";
copy_label(l.c_str());
}
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
/* TODO - awful stuff... we should subclass into gdPluginListChannel and
gdPluginListMaster */
- if (stackType == pluginHost::MASTER_OUT) {
+ if (stackType == pluginHost::StackType::MASTER_OUT) {
G_MainWin->mainIO->setMasterFxOutFull(pluginHost::countPlugins(stackType, ch) > 0);
}
else
- if (stackType == pluginHost::MASTER_IN) {
+ if (stackType == pluginHost::StackType::MASTER_IN) {
G_MainWin->mainIO->setMasterFxInFull(pluginHost::countPlugins(stackType, ch) > 0);
}
else {
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#define GD_PLUGINLIST_H
+#include "../../core/pluginHost.h"
#include "window.h"
public:
giada::m::Channel* ch; // ch == nullptr ? masterOut
- int stackType;
+ giada::m::pluginHost::StackType stackType;
- gdPluginList(int stackType, giada::m::Channel* ch=nullptr);
+ gdPluginList(giada::m::pluginHost::StackType t, giada::m::Channel* ch=nullptr);
~gdPluginList();
/* special callback, passed to browser. When closed (i.e. plugin
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
size_range(450, (G_GUI_UNIT + (G_GUI_OUTER_MARGIN*2)));
resizable(m_list);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
show();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../elems/sampleEditor/rangeTool.h"
#include "../elems/sampleEditor/shiftTool.h"
#include "../elems/mainWindow/keyboard/channel.h"
-#include "gd_warnings.h"
+#include "warnings.h"
#include "sampleEditor.h"
resizable(waveTools);
- gu_setFavicon(this);
+ u::gui::setFavicon(this);
set_non_modal();
copy_label(ch->name.c_str());
if (conf::sampleEditorGridVal == 0)
grid->value(0);
else
- grid->value(grid->find_item(gu_iToString(conf::sampleEditorGridVal).c_str()));
+ grid->value(grid->find_item(u::string::iToString(conf::sampleEditorGridVal).c_str()));
grid->callback(cb_changeGrid, (void*)this);
snap->value(conf::sampleEditorGridOn);
void gdSampleEditor::updateInfo()
{
- string bitDepth = ch->wave->getBits() != 0 ? gu_iToString(ch->wave->getBits()) : "(unknown)";
+ string bitDepth = ch->wave->getBits() != 0 ? u::string::iToString(ch->wave->getBits()) : "(unknown)";
string infoText =
"File: " + ch->wave->getPath() + "\n"
- "Size: " + gu_iToString(ch->wave->getSize()) + " frames\n"
- "Duration: " + gu_iToString(ch->wave->getDuration()) + " seconds\n"
+ "Size: " + u::string::iToString(ch->wave->getSize()) + " frames\n"
+ "Duration: " + u::string::iToString(ch->wave->getDuration()) + " seconds\n"
"Bit depth: " + bitDepth + "\n"
- "Frequency: " + gu_iToString(ch->wave->getRate()) + " Hz\n";
+ "Frequency: " + u::string::iToString(ch->wave->getRate()) + " Hz\n";
info->copy_label(infoText.c_str());
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "../../utils/gui.h"
+#include "../../core/const.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/box.h"
+#include "window.h"
+#include "warnings.h"
+
+
+using namespace giada;
+
+
+void gdAlert(const char *c)
+{
+ Fl_Window *modal = new Fl_Window(
+ (Fl::w() / 2) - 150,
+ (Fl::h() / 2) - 47,
+ 300, 90, "Alert");
+ modal->set_modal();
+ modal->begin();
+ geBox *box = new geBox(10, 10, 280, 40, c);
+ geButton *b = new geButton(210, 60, 80, 20, "Close");
+ modal->end();
+ box->labelsize(G_GUI_FONT_SIZE_BASE);
+ b->callback(__cb_window_closer, (void *)modal);
+ b->shortcut(FL_Enter);
+ u::gui::setFavicon(modal);
+ modal->show();
+}
+
+
+int gdConfirmWin(const char *title, const char *msg)
+{
+ Fl_Window *win = new Fl_Window(
+ (Fl::w() / 2) - 150,
+ (Fl::h() / 2) - 47,
+ 300, 90, title);
+ win->set_modal();
+ win->begin();
+ new geBox(10, 10, 280, 40, msg);
+ geButton *ok = new geButton(212, 62, 80, 20, "Ok");
+ geButton *ko = new geButton(124, 62, 80, 20, "Cancel");
+ win->end();
+ ok->shortcut(FL_Enter);
+ u::gui::setFavicon(win);
+ win->show();
+
+ /* no callbacks here. readqueue() check the event stack. */
+
+ int r = 0;
+ while (true) {
+ Fl_Widget *o = Fl::readqueue();
+ if (!o) Fl::wait();
+ else if (o == ok) {r = 1; break;}
+ else if (o == ko) {r = 0; break;}
+ }
+ //delete win;
+ win->hide();
+ return r;
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+
+#ifndef GD_WARNINGS_H
+#define GD_WARNINGS_H
+
+
+void gdAlert(const char *c);
+int gdConfirmWin(const char *title, const char *msg);
+
+
+#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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 <FL/Fl.H>
+#include "../core/init.h"
+#include "../core/const.h"
+#include "../core/mixer.h"
+#include "../core/channel.h"
+#include "../glue/transport.h"
+#include "../glue/io.h"
+#include "elems/mainWindow/keyboard/channel.h"
+#include "dispatcher.h"
+
+
+namespace giada {
+namespace v {
+namespace dispatcher
+{
+namespace
+{
+bool backspace_ = false;
+bool end_ = false;
+bool enter_ = false;
+bool space_ = false;
+bool esc_ = false;
+
+std::function<void()> signalCb_ = nullptr;
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void perform_(m::Channel* ch, int event)
+{
+ if (event == FL_KEYDOWN)
+ c::io::keyPress(ch, Fl::event_ctrl(), Fl::event_shift(), G_MAX_VELOCITY);
+ else
+ if (event == FL_KEYUP)
+ c::io::keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+/* Walk channels array, trying to match button's bound key with the event. If
+found, trigger the key-press function. */
+
+void dispatchChannels_(int event)
+{
+ for (m::Channel* ch : m::mixer::channels)
+ if (ch->guiChannel->handleKey(event))
+ perform_(ch, event);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void triggerSignalCb_()
+{
+ if (signalCb_ == nullptr)
+ return;
+ signalCb_();
+ signalCb_ = nullptr;
+}
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+void dispatchKey(int event)
+{
+ /* These events come from the keyboard, not from a direct interaction on the
+ UI with the mouse/touch. So the 'gui' parameter is set to false. */
+
+ const bool gui = false;
+
+ if (event == FL_KEYDOWN) {
+ if (Fl::event_key() == FL_BackSpace && !backspace_) {
+ backspace_ = true;
+ c::transport::rewindSeq(gui);
+ }
+ else if (Fl::event_key() == FL_End && !end_) {
+ end_ = true;
+ c::io::toggleInputRec(gui);
+ }
+ else if (Fl::event_key() == FL_Enter && !enter_) {
+ enter_ = true;
+ c::io::toggleActionRec(gui);
+ }
+ else if (Fl::event_key() == ' ' && !space_) {
+ space_ = true;
+ c::transport::startStopSeq(gui);
+ }
+ else if (Fl::event_key() == FL_Escape && !esc_) {
+ esc_ = true;
+ m::init::closeMainWindow();
+ }
+ else
+ triggerSignalCb_();
+ }
+ else if (event == FL_KEYUP) {
+ if (Fl::event_key() == FL_BackSpace)
+ backspace_ = false;
+ else if (Fl::event_key() == FL_End)
+ end_ = false;
+ else if (Fl::event_key() == ' ')
+ space_ = false;
+ else if (Fl::event_key() == FL_Enter)
+ enter_ = false;
+ else if (Fl::event_key() == FL_Escape)
+ esc_ = false;
+ }
+
+ dispatchChannels_(event);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void dispatchTouch(m::Channel* ch, bool status)
+{
+ triggerSignalCb_();
+ perform_(ch, status ? FL_KEYDOWN : FL_KEYUP);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void setSignalCallback(std::function<void()> f)
+{
+ signalCb_ = f;
+}
+
+}}} // giada::v::dispatcher
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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_V_DISPATCHER_H
+#define G_V_DISPATCHER_H
+
+
+#include <functional>
+
+
+namespace giada {
+namespace m
+{
+ class Channel;
+}
+namespace v {
+namespace dispatcher
+{
+void dispatchKey(int event);
+void dispatchTouch(m::Channel* ch, bool status);
+void setSignalCallback(std::function<void()> f);
+}}} // giada::v::dispatcher
+
+
+#endif
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace giada {
namespace m
{
-class Action;
+struct Action;
}
namespace v
{
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* ------------------------------------------------------------------------------
*
-* Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace giada {
namespace m
{
-class Action;
+struct Action;
}
namespace v
{
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
/* print key note label. C C# D D# E F F# G G# A A# B */
- string note = gu_iToString(octave);
+ string note = u::string::iToString(octave);
switch (i % KEYS) {
case (int) Notes::G:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace m
{
class SampleChannel;
-class Action;
+struct Action;
}
namespace v
{
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
namespace m
{
class SampleChannel;
-class Action;
+struct Action;
}
namespace v
{
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * geIdButton
- * Exactly as geButton but with a unique id. Used for the buttons in channels
- * and for FXs.
- *
- * -----------------------------------------------------------------------------
- *
- * 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 "idButton.h"
-
-
-geIdButton::geIdButton(int X, int Y, int W, int H, const char *L,
- const char **imgOff, const char **imgOn)
- : geButton(X, Y, W, H, L, imgOff, imgOn)
-{
-}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * geIdButton
- * Exactly as geButton but with a unique id. Used for the buttons in channels
- * and for FXs.
- *
- * -----------------------------------------------------------------------------
- *
- * 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 GE_ID_BUTTON_H
-#define GE_ID_BUTTON_H
-
-
-#include "button.h"
-
-
-class geIdButton : public geButton
-{
-public:
-
- geIdButton(int X,int Y,int W,int H,const char *L=0,
- const char **imgOff=nullptr, const char **imgOn=nullptr);
-
- int key;
- int id;
-};
-
-
-#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
+using namespace giada;
geBrowser::geBrowser(int x, int y, int w, int h)
string geBrowser::getCurrentDir()
{
- return normalize(gu_getRealPath(m_currentDir));
+ return normalize(u::string::getRealPath(m_currentDir));
}
#else
string sep = G_SLASH_STR;
#endif
- return normalize(gu_getRealPath(m_currentDir + sep + normalize(text(value()))));
+ return normalize(u::string::getRealPath(m_currentDir + sep + normalize(text(value()))));
}
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../core/conf.h"
#include "../../../core/kernelAudio.h"
#include "../../../utils/string.h"
-#include "../../../gui/dialogs/gd_devInfo.h"
+#include "../../../gui/dialogs/devInfo.h"
#include "../basics/box.h"
#include "../basics/choice.h"
#include "../basics/check.h"
using std::string;
+using namespace giada;
using namespace giada::m;
: Fl_Group(X, Y, W, H, "Sound System")
{
begin();
- soundsys = new geChoice(x()+114, y()+9, 250, 20, "System");
- buffersize = new geChoice(x()+114, y()+37, 55, 20, "Buffer size");
- samplerate = new geChoice(x()+309, y()+37, 55, 20, "Sample rate");
- sounddevOut = new geChoice(x()+114, y()+65, 222, 20, "Output device");
- devOutInfo = new geButton(x()+344, y()+65, 20, 20, "?");
- channelsOut = new geChoice(x()+114, y()+93, 55, 20, "Output channels");
- limitOutput = new geCheck (x()+177, y()+97, 55, 20, "Limit output");
- sounddevIn = new geChoice(x()+114, y()+121, 222, 20, "Input device");
- devInInfo = new geButton(x()+344, y()+121, 20, 20, "?");
- channelsIn = new geChoice(x()+114, y()+149, 55, 20, "Input channels");
- delayComp = new geInput (x()+309, y()+149, 55, 20, "Rec delay comp.");
- rsmpQuality = new geChoice(x()+114, y()+177, 250, 20, "Resampling");
- new geBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92,
- "Restart Giada for the changes to take effect.");
+ soundsys = new geChoice(x()+114, y()+9, 250, 20, "System");
+ buffersize = new geChoice(x()+114, y()+37, 55, 20, "Buffer size");
+ samplerate = new geChoice(x()+309, y()+37, 55, 20, "Sample rate");
+ sounddevOut = new geChoice(x()+114, y()+65, 222, 20, "Output device");
+ devOutInfo = new geButton(x()+344, y()+65, 20, 20, "?");
+ channelsOut = new geChoice(x()+114, y()+93, 55, 20, "Output channels");
+ limitOutput = new geCheck (x()+177, y()+97, 55, 20, "Limit output");
+ sounddevIn = new geChoice(x()+114, y()+121, 222, 20, "Input device");
+ devInInfo = new geButton(x()+344, y()+121, 20, 20, "?");
+ channelsIn = new geChoice(x()+114, y()+149, 55, 20, "Input channels");
+ recTriggerLevel = new geInput (x()+309, y()+149, 55, 20, "Rec threshold (dB)");
+ rsmpQuality = new geChoice(x()+114, y()+177, 250, 20, "Resampling");
+ new geBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92, "Restart Giada for the changes to take effect.");
end();
labelsize(G_GUI_FONT_SIZE_BASE);
int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value());
for (int i=0; i<nfreq; i++) {
int freq = kernelAudio::getFreq(sounddevOut->value(), i);
- samplerate->add(gu_iToString(freq).c_str());
+ samplerate->add(u::string::iToString(freq).c_str());
if (freq == conf::samplerate)
samplerate->value(i);
}
buffersize->add("1024");
buffersize->add("2048");
buffersize->add("4096");
- buffersize->showItem(gu_iToString(conf::buffersize).c_str());
+ buffersize->showItem(u::string::iToString(conf::buffersize).c_str());
rsmpQuality->add("Sinc best quality (very slow)");
rsmpQuality->add("Sinc medium quality (slow)");
rsmpQuality->add("Linear (very fast)");
rsmpQuality->value(conf::rsmpQuality);
- delayComp->value(gu_iToString(conf::delayComp).c_str());
- delayComp->type(FL_INT_INPUT);
- delayComp->maximum_size(5);
+ recTriggerLevel->value(u::string::fToString(conf::recTriggerLevel, 1).c_str());
limitOutput->value(conf::limitOutput);
}
/* -------------------------------------------------------------------------- */
-void geTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((geTabAudio*)p)->__cb_deactivate_sounddev(); }
-void geTabAudio::cb_fetchInChans(Fl_Widget *w, void *p) { ((geTabAudio*)p)->__cb_fetchInChans(); }
-void geTabAudio::cb_fetchOutChans(Fl_Widget *w, void *p) { ((geTabAudio*)p)->__cb_fetchOutChans(); }
-void geTabAudio::cb_showInputInfo(Fl_Widget *w, void *p) { ((geTabAudio*)p)->__cb_showInputInfo(); }
-void geTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p) { ((geTabAudio*)p)->__cb_showOutputInfo(); }
+void geTabAudio::cb_deactivate_sounddev(Fl_Widget* w, void* p) { ((geTabAudio*)p)->cb_deactivate_sounddev(); }
+void geTabAudio::cb_fetchInChans(Fl_Widget* w, void* p) { ((geTabAudio*)p)->cb_fetchInChans(); }
+void geTabAudio::cb_fetchOutChans(Fl_Widget* w, void* p) { ((geTabAudio*)p)->cb_fetchOutChans(); }
+void geTabAudio::cb_showInputInfo(Fl_Widget* w, void* p) { ((geTabAudio*)p)->cb_showInputInfo(); }
+void geTabAudio::cb_showOutputInfo(Fl_Widget* w, void* p) { ((geTabAudio*)p)->cb_showOutputInfo(); }
/* -------------------------------------------------------------------------- */
-void geTabAudio::__cb_fetchInChans()
+void geTabAudio::cb_fetchInChans()
{
fetchInChans(sounddevIn->value());
channelsIn->value(0);
/* -------------------------------------------------------------------------- */
-void geTabAudio::__cb_fetchOutChans()
+void geTabAudio::cb_fetchOutChans()
{
fetchOutChans(sounddevOut->value());
channelsOut->value(0);
/* -------------------------------------------------------------------------- */
-void geTabAudio::__cb_showInputInfo()
+void geTabAudio::cb_showInputInfo()
{
unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
new gdDevInfo(dev);
/* -------------------------------------------------------------------------- */
-void geTabAudio::__cb_showOutputInfo()
+void geTabAudio::cb_showOutputInfo()
{
unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
new gdDevInfo(dev);
/* -------------------------------------------------------------------------- */
-void geTabAudio::__cb_deactivate_sounddev()
+void geTabAudio::cb_deactivate_sounddev()
{
/* if the user changes sound system (eg ALSA->JACK) device menu deactivates.
* If it returns to the original sound system, we re-fill the list by
/* if menuItem==0 device in input is disabled. */
if (menuItem == 0) {
- devInInfo ->deactivate();
+ devInInfo->deactivate();
channelsIn->deactivate();
- delayComp ->deactivate();
+ recTriggerLevel->deactivate();
return;
}
- devInInfo ->activate();
+ devInInfo->activate();
channelsIn->activate();
- delayComp ->activate();
+ recTriggerLevel->activate();
channelsIn->clear();
return;
}
for (unsigned i=0; i<chs; i+=2) {
- string tmp = gu_iToString(i+1) + "-" + gu_iToString(i+2);
+ string tmp = u::string::iToString(i+1) + "-" + u::string::iToString(i+2);
channelsIn->add(tmp.c_str());
}
channelsIn->value(conf::channelsIn);
return;
}
for (unsigned i=0; i<chs; i+=2) {
- string tmp = gu_iToString(i+1) + "-" + gu_iToString(i+2);
+ string tmp = u::string::iToString(i+1) + "-" + u::string::iToString(i+2);
channelsOut->add(tmp.c_str());
}
channelsOut->value(conf::channelsOut);
if (conf::soundDeviceOut == -1)
conf::soundDeviceOut = 0;
- int bufsize = atoi(buffersize->text());
- if (bufsize % 2 != 0) bufsize++;
- if (bufsize < 8) bufsize = 8;
- if (bufsize > 8192) bufsize = 8192;
- conf::buffersize = bufsize;
+ conf::buffersize = std::atoi(buffersize->text());
+ conf::recTriggerLevel = std::atof(recTriggerLevel->value());
- const Fl_Menu_Item *i = nullptr;
+ const Fl_Menu_Item* i = nullptr;
i = samplerate->mvalue(); // mvalue() returns a pointer to the last menu item that was picked
- if (i)
- conf::samplerate = atoi(i->label());
-
- conf::delayComp = atoi(delayComp->value());
+ if (i != nullptr)
+ conf::samplerate = std::atoi(i->label());
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
private:
- static void cb_deactivate_sounddev(Fl_Widget *w, void *p);
- static void cb_fetchInChans (Fl_Widget *w, void *p);
- static void cb_fetchOutChans (Fl_Widget *w, void *p);
- static void cb_showInputInfo (Fl_Widget *w, void *p);
- static void cb_showOutputInfo (Fl_Widget *w, void *p);
- inline void __cb_deactivate_sounddev();
- inline void __cb_fetchInChans();
- inline void __cb_fetchOutChans();
- inline void __cb_showInputInfo();
- inline void __cb_showOutputInfo();
+ static void cb_deactivate_sounddev(Fl_Widget* w, void* p);
+ static void cb_fetchInChans (Fl_Widget* w, void* p);
+ static void cb_fetchOutChans (Fl_Widget* w, void* p);
+ static void cb_showInputInfo (Fl_Widget* w, void* p);
+ static void cb_showOutputInfo (Fl_Widget* w, void* p);
+ void cb_deactivate_sounddev();
+ void cb_fetchInChans();
+ void cb_fetchOutChans();
+ void cb_showInputInfo();
+ void cb_showOutputInfo();
void fetchSoundDevs();
void fetchInChans(int menuItem);
void fetchOutChans(int menuItem);
- int findMenuDevice(geChoice *m, int device);
+ int findMenuDevice(geChoice* m, int device);
int soundsysInitValue;
public:
- geChoice *soundsys;
- geChoice *samplerate;
- geChoice *rsmpQuality;
- geChoice *sounddevIn;
- geButton *devInInfo;
- geChoice *channelsIn;
- geChoice *sounddevOut;
- geButton *devOutInfo;
- geChoice *channelsOut;
- geCheck *limitOutput;
- geChoice *buffersize;
- geInput *delayComp;
+ geChoice* soundsys;
+ geChoice* buffersize;
+ geChoice* samplerate;
+ geChoice* sounddevOut;
+ geButton* devOutInfo;
+ geChoice* channelsOut;
+ geCheck* limitOutput;
+ geChoice* sounddevIn;
+ geButton* devInInfo;
+ geChoice* channelsIn;
+ geInput* recTriggerLevel;
+ geChoice* rsmpQuality;
geTabAudio(int x, int y, int w, int h);
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
+using namespace giada;
using namespace giada::m;
portOut->add("(disabled)");
for (unsigned i=0; i<kernelMidi::countOutPorts(); i++)
- portOut->add(gu_removeFltkChars(kernelMidi::getOutPortName(i)).c_str());
+ portOut->add(u::gui::removeFltkChars(kernelMidi::getOutPortName(i)).c_str());
portOut->value(conf::midiPortOut+1); // +1 because midiPortOut=-1 is '(disabled)'
}
portIn->add("(disabled)");
for (unsigned i=0; i<kernelMidi::countInPorts(); i++)
- portIn->add(gu_removeFltkChars(kernelMidi::getInPortName(i)).c_str());
+ portIn->add(u::gui::removeFltkChars(kernelMidi::getInPortName(i)).c_str());
portIn->value(conf::midiPortIn+1); // +1 because midiPortIn=-1 is '(disabled)'
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../core/const.h"
#include "../../../core/conf.h"
#include "../../../core/graphics.h"
-#include "../../../core/pluginHost.h"
+#include "../../../core/pluginManager.h"
#include "../../../glue/plugin.h"
#include "../../../utils/string.h"
#include "../../../utils/fs.h"
#include "../../../utils/gui.h"
#include "../../dialogs/window.h"
-#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/mainWindow.h"
#include "../../dialogs/browser/browserDir.h"
#include "../basics/box.h"
#include "../basics/radio.h"
using std::string;
+using namespace giada;
using namespace giada::m;
void geTabPlugins::refreshCount()
{
- string scanLabel = "Scan (" + gu_iToString(pluginHost::countAvailablePlugins()) + " found)";
+ string scanLabel = "Scan (" + u::string::iToString(pluginManager::countAvailablePlugins()) + " found)";
m_scanButton->label(scanLabel.c_str());
}
{
std::function<void(float)> callback = [this] (float progress)
{
- string l = "Scan in progress (" + gu_iToString((int)(progress*100)) + "%). Please wait...";
+ string l = "Scan in progress (" + u::string::iToString((int)(progress*100)) + "%). Please wait...";
m_info->label(l.c_str());
Fl::wait();
};
m_info->show();
- pluginHost::scanDirs(m_folderPath->value(), callback);
- pluginHost::saveList(gu_getHomePath() + G_SLASH + "plugins.xml");
+ pluginManager::scanDirs(m_folderPath->value(), callback);
+ pluginManager::saveList(gu_getHomePath() + G_SLASH + "plugins.xml");
m_info->hide();
refreshCount();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/fl_draw.H>
#include "../../../core/const.h"
+#include "../../../core/recManager.h"
#include "../../../core/mixer.h"
#include "../../../core/clock.h"
+#include "../../../utils/gui.h"
#include "beatMeter.h"
-using namespace giada::m;
+namespace giada {
+namespace v
+{
+geBeatMeter::geBeatMeter(int x, int y, int w, int h, const char* l)
+: Fl_Box(x, y, w, h, l)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
-geBeatMeter::geBeatMeter(int x, int y, int w, int h, const char *L)
- : Fl_Box(x, y, w, h, L) {}
+Fl_Color geBeatMeter::getCursorColor()
+{
+ if (m::clock::getStatus() == ClockStatus::WAITING && u::gui::shouldBlink())
+ return FL_BACKGROUND_COLOR;
+ return G_COLOR_LIGHT_1;
+}
/* -------------------------------------------------------------------------- */
void geBeatMeter::draw()
{
- int cursorW = w() / G_MAX_BEATS;
- int greyX = clock::getBeats() * cursorW;
+ using namespace giada::m;
+
+ int cursorW = w() / G_MAX_BEATS;
+ int greyX = clock::getBeats() * cursorW;
- fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border
- fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR); // bg
- fl_rectf(x()+(clock::getCurrentBeat()*cursorW)+3, y()+3, cursorW-5, h()-6,
- G_COLOR_LIGHT_1); // cursor
+ /* Border and background. */
+
+ fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);
+ fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR);
- /* beat cells */
+ /* Cursor. */
- fl_color(G_COLOR_GREY_4);
- for (int i=1; i<=clock::getBeats(); i++)
- fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2);
+ fl_rectf(x() + (clock::getCurrentBeat() * cursorW) + 3, y() + 3, cursorW - 5, h() - 6, getCursorColor());
- /* bar line */
+ /* Beat cells. */
- fl_color(G_COLOR_LIGHT_1);
- int delta = clock::getBeats() / clock::getBars();
- for (int i=1; i<clock::getBars(); i++)
- fl_line(x()+cursorW*(i*delta), y()+1, x()+cursorW*(i*delta), y()+h()-2);
+ fl_color(G_COLOR_GREY_4);
+ for (int i=1; i<=clock::getBeats(); i++)
+ fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2);
- /* unused grey area */
+ /* Bar line. */
- fl_rectf(x()+greyX+1, y()+1, w()-greyX-1, h()-2, G_COLOR_GREY_4);
+ fl_color(G_COLOR_LIGHT_1);
+ int delta = clock::getBeats() / clock::getBars();
+ for (int i=1; i<clock::getBars(); i++)
+ fl_line(x()+cursorW*(i*delta), y()+1, x()+cursorW*(i*delta), y()+h()-2);
+
+ /* Unused grey area. */
+
+ fl_rectf(x()+greyX+1, y()+1, w()-greyX-1, h()-2, G_COLOR_GREY_4);
}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/Fl_Box.H>
+namespace giada {
+namespace v
+{
class geBeatMeter : public Fl_Box
{
public:
- geBeatMeter(int X,int Y,int W,int H,const char *L=0);
- void draw();
+ geBeatMeter(int x, int y, int w, int h, const char* l=nullptr);
+ void draw();
+
+private:
+
+ Fl_Color getCursorColor();
};
+}} // giada::v::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../core/pluginHost.h"
#include "../../../../utils/gui.h"
#include "../../../../glue/channel.h"
-#include "../../../dialogs/gd_mainWindow.h"
+#include "../../../dialogs/mainWindow.h"
#include "../../../dialogs/pluginList.h"
-#include "../../basics/idButton.h"
+#include "../../basics/button.h"
#include "../../basics/dial.h"
#include "../../basics/statusButton.h"
#include "column.h"
geChannel::geChannel(int X, int Y, int W, int H, giada::m::Channel* ch)
- : Fl_Group(X, Y, W, H, nullptr),
- ch (ch)
+: Fl_Group (X, Y, W, H, nullptr),
+ ch (ch)
{
}
#ifdef WITH_VST
void geChannel::cb_openFxWindow()
{
- gu_openSubWindow(G_MainWin, new gdPluginList(m::pluginHost::CHANNEL, ch), WID_FX_LIST);
+ u::gui::openSubWindow(G_MainWin, new gdPluginList(m::pluginHost::StackType::CHANNEL, ch), WID_FX_LIST);
}
#endif
/* -------------------------------------------------------------------------- */
-int geChannel::keyPress(int e)
-{
- return handleKey(e, ch->key);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
int geChannel::getColumnIndex()
{
void geChannel::blink()
{
- if (gu_getBlinker() > 6)
+ if (u::gui::shouldBlink())
mainButton->setPlayMode();
else
mainButton->setDefaultMode();
/* -------------------------------------------------------------------------- */
-void geChannel::setColorsByStatus(ChannelStatus playStatus, ChannelStatus recStatus)
+
+void geChannel::setColorsByStatus()
{
- switch (playStatus) {
+ switch (ch->status) {
case ChannelStatus::OFF:
case ChannelStatus::EMPTY:
mainButton->setDefaultMode();
break;
case ChannelStatus::PLAY:
mainButton->setPlayMode();
- button->imgOn = channelStop_xpm;
- button->imgOff = channelPlay_xpm;
- button->redraw();
+ if (!button->value()) { // If not manually pressed (it would interfere)
+ button->imgOn = channelStop_xpm;
+ button->imgOff = channelPlay_xpm;
+ button->redraw();
+ }
break;
case ChannelStatus::WAIT:
blink();
default: break;
}
- switch (recStatus) {
+ switch (ch->recStatus) {
case ChannelStatus::WAIT:
blink();
break;
/* -------------------------------------------------------------------------- */
-int geChannel::handleKey(int e, int key)
+bool geChannel::handleKey(int e)
{
- int ret;
- if (e == FL_KEYDOWN && button->value()) // key already pressed! skip it
- ret = 1;
- else
- if (Fl::event_key() == key && !button->value()) {
- button->take_focus(); // move focus to this button
- button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state
- button->do_callback(); // invoke the button's callback
- ret = 1;
- }
- else
- ret = 0;
+ if (Fl::event_key() != ch->key)
+ return false;
- if (Fl::event_key() == key)
- button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state
+ if (e == FL_KEYDOWN && !button->value()) { // Key not already pressed
+ button->take_focus(); // Move focus to this button
+ button->value(1);
+ return true;
+ }
- return ret;
+ if (e == FL_KEYUP) {
+ button->value(0);
+ return true;
+ }
+
+ return false;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../core/channel.h"
-class geIdButton;
class geChannelStatus;
class geButton;
class geChannelButton;
class geChannel : public Fl_Group
{
+public:
+
+ geChannel(int x, int y, int w, int h, giada::m::Channel* ch);
+
+ /* reset
+ Resets channel to initial status. */
+
+ virtual void reset() = 0;
+
+ /* update
+ Updates the label of sample button and everything else such as 'R' button,
+ key box and so on, according to global values. */
+
+ virtual void update() = 0;
+
+ /* refresh
+ Updates graphics. */
+
+ virtual void refresh() = 0;
+
+ /* changeSize
+ Changes channel's size according to a template (x1, x2, ...). */
+
+ virtual void changeSize(int h);
+
+ /* getColumnIndex
+ Returns the numeric index of the column in which this channel is located. */
+
+ int getColumnIndex();
+
+ int getSize();
+
+ /* handleKey
+ Performs some UI-related operations when the bound key is pressed. Returns
+ whether the bound key has been pressed or not. */
+
+ bool handleKey(int e);
+
+ giada::m::Channel* ch;
+
+ geButton* button;
+ geChannelStatus* status;
+ geButton* arm;
+ geChannelButton* mainButton;
+ geButton* mute;
+ geButton* solo;
+ geDial* vol;
+#ifdef WITH_VST
+ geStatusButton* fx;
+#endif
+
protected:
/* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of
static void cb_solo(Fl_Widget* v, void* p);
static void cb_changeVol(Fl_Widget* v, void* p);
#ifdef WITH_VST
- static void cb_openFxWindow(Fl_Widget* v, void* p);
+ static void cb_openFxWindow(Fl_Widget* v, void* p);
#endif
void cb_mute();
void cb_arm();
#endif
/* blink
- * blink button when channel is in wait/ending status. */
+ Blinks button when channel is in wait/ending status. */
void blink();
/* setColorByStatus
- * update colors depending on channel status. */
-
- void setColorsByStatus(giada::ChannelStatus chan, giada::ChannelStatus rec);
+ Updates colors depending on channel status. */
- /* handleKey
- * method wrapped by virtual handle(int e). */
-
- int handleKey(int e, int key);
+ void setColorsByStatus();
/* packWidgets
Spread widgets across available space. */
void packWidgets();
-
-public:
-
- geChannel(int x, int y, int w, int h, giada::m::Channel* ch);
-
- /* reset
- * reset channel to initial status. */
-
- virtual void reset() = 0;
-
- /* update
- * update the label of sample button and everything else such as 'R'
- * button, key box and so on, according to global values. */
-
- virtual void update() = 0;
-
- /* refresh
- * update graphics. */
-
- virtual void refresh() = 0;
-
- /* changeSize
- Changes channel's size according to a template (x1, x2, ...). */
-
- virtual void changeSize(int h);
-
- /* keypress
- * what to do when the corresponding key is pressed. */
-
- int keyPress(int event);
-
- /* getColumnIndex
- * return the numeric index of the column in which this channel is
- * located. */
-
- int getColumnIndex();
-
- int getSize();
-
- giada::m::Channel* ch;
-
- geIdButton* button;
- geChannelStatus* status;
- geButton* arm;
- geChannelButton* mainButton;
- geButton* mute;
- geButton* solo;
- geDial* vol;
-#ifdef WITH_VST
- geStatusButton* fx;
-#endif
};
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using namespace giada;
-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)
+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)
{
- box(G_CUSTOM_BORDER_BOX);
- textsize(G_GUI_FONT_SIZE_BASE);
- textcolor(G_COLOR_LIGHT_2);
- color(G_COLOR_GREY_2);
-
- add("Loop . basic", 0, cb_changeMode, (void*) ChannelMode::LOOP_BASIC);
- add("Loop . once", 0, cb_changeMode, (void*) ChannelMode::LOOP_ONCE);
- add("Loop . once . bar", 0, cb_changeMode, (void*) ChannelMode::LOOP_ONCE_BAR);
- add("Loop . repeat", 0, cb_changeMode, (void*) ChannelMode::LOOP_REPEAT);
- add("Oneshot . basic", 0, cb_changeMode, (void*) ChannelMode::SINGLE_BASIC);
- add("Oneshot . press", 0, cb_changeMode, (void*) ChannelMode::SINGLE_PRESS);
- add("Oneshot . retrig", 0, cb_changeMode, (void*) ChannelMode::SINGLE_RETRIG);
- add("Oneshot . endless", 0, cb_changeMode, (void*) ChannelMode::SINGLE_ENDLESS);
+ box(G_CUSTOM_BORDER_BOX);
+ textsize(G_GUI_FONT_SIZE_BASE);
+ textcolor(G_COLOR_LIGHT_2);
+ color(G_COLOR_GREY_2);
+
+ add("Loop . basic", 0, cb_changeMode, (void*) ChannelMode::LOOP_BASIC);
+ add("Loop . once", 0, cb_changeMode, (void*) ChannelMode::LOOP_ONCE);
+ add("Loop . once . bar", 0, cb_changeMode, (void*) ChannelMode::LOOP_ONCE_BAR);
+ add("Loop . repeat", 0, cb_changeMode, (void*) ChannelMode::LOOP_REPEAT);
+ add("Oneshot . basic", 0, cb_changeMode, (void*) ChannelMode::SINGLE_BASIC);
+ add("Oneshot . press", 0, cb_changeMode, (void*) ChannelMode::SINGLE_PRESS);
+ add("Oneshot . retrig", 0, cb_changeMode, (void*) ChannelMode::SINGLE_RETRIG);
+ add("Oneshot . endless", 0, cb_changeMode, (void*) ChannelMode::SINGLE_ENDLESS);
}
/* -------------------------------------------------------------------------- */
-void geChannelMode::draw() {
- fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border
- switch (ch->mode) {
- case ChannelMode::LOOP_BASIC:
- fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1);
- break;
- case ChannelMode::LOOP_ONCE:
- fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1);
- break;
- case ChannelMode::LOOP_ONCE_BAR:
- fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1);
- break;
- case ChannelMode::LOOP_REPEAT:
- fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1);
- break;
- case ChannelMode::SINGLE_BASIC:
- fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1);
- break;
- case ChannelMode::SINGLE_PRESS:
- fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1);
- break;
- case ChannelMode::SINGLE_RETRIG:
- fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1);
- break;
- case ChannelMode::SINGLE_ENDLESS:
- fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1);
- break;
- }
+void geChannelMode::draw()
+{
+ fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border
+ switch (ch->mode) {
+ case ChannelMode::LOOP_BASIC:
+ fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::LOOP_ONCE:
+ fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::LOOP_ONCE_BAR:
+ fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::LOOP_REPEAT:
+ fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::SINGLE_BASIC:
+ fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::SINGLE_PRESS:
+ fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::SINGLE_RETRIG:
+ fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1);
+ break;
+ case ChannelMode::SINGLE_ENDLESS:
+ fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1);
+ break;
+ }
}
void geChannelMode::__cb_changeMode(int mode)
{
- ch->mode = static_cast<ChannelMode>(mode);
+ ch->mode = static_cast<ChannelMode>(mode);
- /* What to do when the channel is playing and you change the mode? Nothing,
- since v0.5.3. Just refresh the action editor window, in case it's open. */
+ /* What to do when the channel is playing and you change the mode? Nothing,
+ since v0.5.3. Just refresh the action editor window, in case it's open. */
- gu_refreshActionEditor();
+ u::gui::refreshActionEditor();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../utils/log.h"
#include "../../../../utils/fs.h"
#include "../../../../utils/string.h"
-#include "../../../dialogs/gd_warnings.h"
+#include "../../../dialogs/warnings.h"
#include "../../../elems/basics/boxtypes.h"
#include "../../../elems/basics/resizerBar.h"
#include "keyboard.h"
using namespace giada;
-geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard* parent)
+geColumn::geColumn(int X, int Y, int W, int H, int index, v::geKeyboard* parent)
: Fl_Group(X, Y, W, H),
m_parent(parent),
m_index (index)
return 1;
}
case FL_PASTE: { // handle actual drop (paste) operation
- vector<string> paths;
- gu_split(Fl::event_text(), "\n", &paths);
+ vector<string> paths = u::string::split(Fl::event_text(), "\n");
bool fails = false;
int result = 0;
for (string& path : paths) {
gu_log("[geColumn::handle] loading %s...\n", path.c_str());
+ // TODO - c::channel::addAndLoad(...)
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));
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class geButton;
class geChannel;
class geResizerBar;
+namespace giada {
+namespace v
+{
class geKeyboard;
+}}
class geColumn : public Fl_Group
geButton* m_addChannelBtn;
geResizerBar* m_resizer;
- geKeyboard* m_parent;
+ giada::v::geKeyboard* m_parent;
int m_index;
public:
- geColumn(int x, int y, int w, int h, int index, geKeyboard* parent);
+ geColumn(int x, int y, int w, int h, int index, giada::v::geKeyboard* parent);
~geColumn();
/* addChannel
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../glue/transport.h"
#include "../../../../glue/io.h"
#include "../../../../utils/log.h"
-#include "../../../dialogs/gd_warnings.h"
+#include "../../../dialogs/warnings.h"
+#include "../../../dispatcher.h"
#include "../../basics/boxtypes.h"
#include "column.h"
#include "sampleChannel.h"
#include "keyboard.h"
-using namespace giada;
-
-
+namespace giada {
+namespace v
+{
int geKeyboard::indexColumn = 0;
geKeyboard::geKeyboard(int X, int Y, int W, int H)
-: Fl_Scroll (X, Y, W, H),
- bckspcPressed(false),
- endPressed (false),
- spacePressed (false),
- addColumnBtn (nullptr)
+: Fl_Scroll (X, Y, W, H),
+ addColumnBtn(nullptr)
{
color(G_COLOR_GREY_1);
type(Fl_Scroll::BOTH_ALWAYS);
/* -------------------------------------------------------------------------- */
-/* TODO - the following event handling for play, stop, rewind, start rec and
-so on should be moved to the proper widget: gdMainWindow or (better) geController. */
int geKeyboard::handle(int e)
{
- using namespace giada::c;
-
- int ret = Fl_Group::handle(e); // assume the buttons won't handle the Keyboard events
switch (e) {
case FL_FOCUS:
case FL_UNFOCUS: {
- ret = 1; // enables receiving Keyboard events
- break;
+ return 1; // Enables receiving Keyboard events
}
- case FL_SHORTCUT: // in case widget that isn't ours has focus
+ case FL_SHORTCUT: // In case widget that isn't ours has focus
case FL_KEYDOWN: // Keyboard key pushed
case FL_KEYUP: { // Keyboard key released
-
- /* rewind session. Avoid retrigs */
-
- if (e == FL_KEYDOWN) {
- if (Fl::event_key() == FL_BackSpace && !bckspcPressed) {
- bckspcPressed = true;
- transport::rewindSeq(false); // not from GUI
- ret = 1;
- break;
- }
- else if (Fl::event_key() == FL_End && !endPressed) {
- endPressed = true;
- io::startStopInputRec(false); // not from GUI
- ret = 1;
- break;
- }
- else if (Fl::event_key() == FL_Enter && !enterPressed) {
- enterPressed = true;
- io::startStopActionRec(false); // not from GUI
- ret = 1;
- break;
- }
- else if (Fl::event_key() == ' ' && !spacePressed) {
- spacePressed = true;
- transport::startStopSeq(false); // unot from GUI
- ret = 1;
- break;
- }
- }
- else if (e == FL_KEYUP) {
- if (Fl::event_key() == FL_BackSpace)
- bckspcPressed = false;
- else if (Fl::event_key() == FL_End)
- endPressed = false;
- else if (Fl::event_key() == ' ')
- spacePressed = false;
- else if (Fl::event_key() == FL_Enter)
- enterPressed = false;
- }
-
- /* Walk button arrays, trying to match button's label with the Keyboard event.
- * If found, set that button's value() based on up/down event,
- * and invoke that button's callback() */
-
- for (unsigned i=0; i<columns.size(); i++)
- for (int k=1; k<columns.at(i)->children(); k++)
- ret &= static_cast<geChannel*>(columns.at(i)->child(k))->keyPress(e);
- break;
+ dispatcher::dispatchKey(e);
+ return 1;
}
}
- return ret;
+ return Fl_Group::handle(e); // Assume the buttons won't handle the Keyboard events
}
{
return columns.at(i);
}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class geSampleChannel;
+namespace giada {
+namespace v
+{
class geKeyboard : public Fl_Scroll
{
private:
static void cb_addColumn (Fl_Widget* v, void* p);
inline void __cb_addColumn(int width=G_DEFAULT_COLUMN_WIDTH);
- bool bckspcPressed;
- bool endPressed;
- bool spacePressed;
- bool enterPressed;
-
/* indexColumn
* the last index used for column. */
int getColumnWidth(int i);
};
+}} // giada::v::
#endif
#include "../../../../glue/channel.h"
#include "../../../../glue/io.h"
#include "../../../../glue/recorder.h"
-#include "../../../dialogs/gd_mainWindow.h"
+#include "../../../dispatcher.h"
+#include "../../../dialogs/mainWindow.h"
#include "../../../dialogs/channelNameInput.h"
-#include "../../../dialogs/gd_warnings.h"
-#include "../../../dialogs/gd_keyGrabber.h"
+#include "../../../dialogs/warnings.h"
+#include "../../../dialogs/keyGrabber.h"
#include "../../../dialogs/pluginList.h"
#include "../../../dialogs/actionEditor/midiActionEditor.h"
#include "../../../dialogs/midiIO/midiInputChannel.h"
#include "../../../dialogs/midiIO/midiOutputMidiCh.h"
#include "../../basics/boxtypes.h"
-#include "../../basics/idButton.h"
+#include "../../basics/button.h"
#include "../../basics/statusButton.h"
#include "../../basics/dial.h"
#include "column.h"
case Menu::__END_RESIZE_SUBMENU__:
break;
case Menu::EDIT_ACTIONS:
- gu_openSubWindow(G_MainWin, new v::gdMidiActionEditor(ch), WID_ACTION_EDITOR);
+ u::gui::openSubWindow(G_MainWin, new v::gdMidiActionEditor(ch), WID_ACTION_EDITOR);
break;
case Menu::CLEAR_ACTIONS_ALL:
c::recorder::clearAllActions(gch);
break;
case Menu::SETUP_KEYBOARD_INPUT:
- gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
+ u::gui::openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
break;
case Menu::SETUP_MIDI_INPUT:
- gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
+ u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
break;
case Menu::SETUP_MIDI_OUTPUT:
- gu_openSubWindow(G_MainWin, new gdMidiOutputMidiCh(ch), 0);
+ u::gui::openSubWindow(G_MainWin, new gdMidiOutputMidiCh(ch), 0);
break;
case Menu::RESIZE_H1:
gch->changeSize(G_GUI_CHANNEL_H_1);
c::channel::cloneChannel(gch->ch);
break;
case Menu::RENAME_CHANNEL:
- gu_openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
+ u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
break;
case Menu::DELETE_CHANNEL:
c::channel::deleteChannel(gch->ch);
int delta = 120; // (5 widgets * G_GUI_UNIT) + (5 paddings * 4)
#endif
- button = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+ button = new geButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
arm = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, H, "-- MIDI --");
mute = new geButton(mainButton->x()+mainButton->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", muteOff_xpm, muteOn_xpm);
void geMidiChannel::cb_button()
{
- using namespace giada;
-
- if (button->value())
- c::io::keyPress(static_cast<m::MidiChannel*>(ch), Fl::event_ctrl(), Fl::event_shift(), 0);
+ v::dispatcher::dispatchTouch(ch, button->value());
}
void geMidiChannel::refresh()
{
- setColorsByStatus(ch->status, ch->recStatus);
+ setColorsByStatus();
if (m::recorder::isActive() && ch->armed)
mainButton->setActionRecordMode();
mainButton->redraw();
label = mch->name.c_str();
if (mch->midiOut)
- label += " (ch " + gu_iToString(mch->midiOutChan + 1) + " out)";
+ label += " (ch " + u::string::iToString(mch->midiOutChan + 1) + " out)";
mainButton->label(label.c_str());
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../glue/recorder.h"
#include "../../../../glue/storage.h"
#include "../../../../utils/gui.h"
-#include "../../../dialogs/gd_mainWindow.h"
-#include "../../../dialogs/gd_keyGrabber.h"
+#include "../../../dispatcher.h"
+#include "../../../dialogs/mainWindow.h"
+#include "../../../dialogs/keyGrabber.h"
#include "../../../dialogs/sampleEditor.h"
#include "../../../dialogs/channelNameInput.h"
-#include "../../../dialogs/gd_warnings.h"
+#include "../../../dialogs/warnings.h"
#include "../../../dialogs/actionEditor/sampleActionEditor.h"
#include "../../../dialogs/browser/browserSave.h"
#include "../../../dialogs/browser/browserLoad.h"
#include "../../../dialogs/midiIO/midiOutputSampleCh.h"
#include "../../../dialogs/midiIO/midiInputChannel.h"
#include "../../basics/boxtypes.h"
-#include "../../basics/idButton.h"
+#include "../../basics/button.h"
#include "../../basics/statusButton.h"
#include "../../basics/dial.h"
#include "channelStatus.h"
case Menu::LOAD_SAMPLE: {
gdWindow *w = new gdBrowserLoad(m::conf::browserX, m::conf::browserY,
m::conf::browserW, m::conf::browserH, "Browse sample",
- m::conf::samplePath.c_str(), glue_loadSample, gch->ch);
- gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+ m::conf::samplePath.c_str(), c::storage::loadSample, gch->ch);
+ u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
break;
}
case Menu::EXPORT_SAMPLE: {
gdWindow *w = new gdBrowserSave(m::conf::browserX, m::conf::browserY,
m::conf::browserW, m::conf::browserH, "Save sample",
- m::conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
- gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+ m::conf::samplePath.c_str(), "", c::storage::saveSample, gch->ch);
+ u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
break;
}
case Menu::SETUP_KEYBOARD_INPUT: {
break;
}
case Menu::SETUP_MIDI_INPUT: {
- gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
+ u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
break;
}
case Menu::SETUP_MIDI_OUTPUT: {
- gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(ch), 0);
+ u::gui::openSubWindow(G_MainWin, new gdMidiOutputSampleCh(ch), 0);
break;
}
case Menu::EDIT_SAMPLE: {
- gu_openSubWindow(G_MainWin, new gdSampleEditor(ch), WID_SAMPLE_EDITOR);
+ u::gui::openSubWindow(G_MainWin, new gdSampleEditor(ch), WID_SAMPLE_EDITOR);
break;
}
case Menu::EDIT_ACTIONS: {
- gu_openSubWindow(G_MainWin, new v::gdSampleActionEditor(ch), WID_ACTION_EDITOR);
+ u::gui::openSubWindow(G_MainWin, new v::gdSampleActionEditor(ch), WID_ACTION_EDITOR);
break;
}
case Menu::CLEAR_ACTIONS:
break;
}
case Menu::RENAME_CHANNEL: {
- gu_openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
+ u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
break;
}
case Menu::FREE_CHANNEL: {
{
begin();
- button = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+ button = new geButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
arm = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
status = new geChannelStatus(arm->x()+arm->w()+4, y(), G_GUI_UNIT, H, ch);
mainButton = new geSampleChannelButton(status->x()+status->w()+4, y(), G_GUI_UNIT, H, "-- no sample --");
/* -------------------------------------------------------------------------- */
-void geSampleChannel::cb_button (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_button(); }
-void geSampleChannel::cb_openMenu (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_openMenu(); }
-void geSampleChannel::cb_readActions (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_readActions(); }
+void geSampleChannel::cb_button (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_button(); }
+void geSampleChannel::cb_openMenu (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_openMenu(); }
+void geSampleChannel::cb_readActions(Fl_Widget* v, void* p) { ((geSampleChannel*)p)->cb_readActions(); }
/* -------------------------------------------------------------------------- */
void geSampleChannel::cb_button()
{
- using namespace giada;
-
- if (button->value()) // pushed, max velocity (127 i.e. 0x7f)
- c::io::keyPress(ch, Fl::event_ctrl(), Fl::event_shift(), 0x7F);
- else // released
- c::io::keyRelease(ch, Fl::event_ctrl(), Fl::event_shift());
+ v::dispatcher::dispatchTouch(ch, button->value());
}
if (!mainButton->visible()) // mainButton invisible? status too (see below)
return;
- setColorsByStatus(ch->status, ch->recStatus);
+ setColorsByStatus();
if (static_cast<m::SampleChannel*>(ch)->wave != nullptr) {
if (m::mixer::recording && ch->armed)
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../../utils/string.h"
#include "../../../../utils/fs.h"
#include "../../../../glue/channel.h"
-#include "../../../dialogs/gd_mainWindow.h"
+#include "../../../dialogs/mainWindow.h"
#include "sampleChannel.h"
#include "keyboard.h"
#include "sampleChannelButton.h"
case FL_PASTE: {
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())));
+ int result = c::channel::loadChannel(ch, u::string::trim(gu_stripFileUrl(Fl::event_text())));
if (result != G_RES_OK)
G_MainWin->keyboard->printChannelMessage(result);
ret = 1;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
-* Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../elems/soundMeter.h"
#include "../../elems/basics/statusButton.h"
#include "../../elems/basics/dial.h"
-#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/mainWindow.h"
#include "../../dialogs/pluginList.h"
#include "mainIO.h"
-extern gdMainWindow *G_MainWin;
-
-
-using namespace giada::m;
+extern gdMainWindow* G_MainWin;
+namespace giada {
+namespace v
+{
geMainIO::geMainIO(int x, int y)
: Fl_Group(x, y, 396, 20)
{
#if defined(WITH_VST)
masterFxIn = new geStatusButton (x, y, 20, 20, fxOff_xpm, fxOn_xpm);
- inVol = new geDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20);
+ inVol = new geDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20);
inMeter = new geSoundMeter(inVol->x()+inVol->w()+4, y+4, 140, 12);
inToOut = new geButton (inMeter->x()+inMeter->w()+4, y+4, 12, 12, "", inputToOutputOff_xpm, inputToOutputOn_xpm);
outMeter = new geSoundMeter(inToOut->x()+inToOut->w()+4, y+4, 140, 12);
- outVol = new geDial (outMeter->x()+outMeter->w()+4, y, 20, 20);
+ outVol = new geDial (outMeter->x()+outMeter->w()+4, y, 20, 20);
masterFxOut = new geStatusButton (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm);
#else
- inVol = new geDial (x+62, y, 20, 20);
+ inVol = new geDial (x+62, y, 20, 20);
inMeter = new geSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 12);
outMeter = new geSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 12);
- outVol = new geDial (outMeter->x()+outMeter->w()+4, y, 20, 20);
+ outVol = new geDial (outMeter->x()+outMeter->w()+4, y, 20, 20);
#endif
end();
resizable(nullptr); // don't resize any widget
outVol->callback(cb_outVol, (void*)this);
- outVol->value(mixer::outVol);
+ outVol->value(m::mixer::outVol.load());
inVol->callback(cb_inVol, (void*)this);
- inVol->value(mixer::inVol);
+ inVol->value(m::mixer::inVol.load());
#ifdef WITH_VST
masterFxOut->callback(cb_masterFxOut, (void*)this);
/* -------------------------------------------------------------------------- */
-void geMainIO::cb_outVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_outVol(); }
-void geMainIO::cb_inVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_inVol(); }
+void geMainIO::cb_outVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->cb_outVol(); }
+void geMainIO::cb_inVol (Fl_Widget *v, void *p) { ((geMainIO*)p)->cb_inVol(); }
#ifdef WITH_VST
-void geMainIO::cb_masterFxOut(Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_masterFxOut(); }
-void geMainIO::cb_masterFxIn (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_masterFxIn(); }
-void geMainIO::cb_inToOut (Fl_Widget *v, void *p) { ((geMainIO*)p)->__cb_inToOut(); }
+void geMainIO::cb_masterFxOut(Fl_Widget *v, void *p) { ((geMainIO*)p)->cb_masterFxOut(); }
+void geMainIO::cb_masterFxIn (Fl_Widget *v, void *p) { ((geMainIO*)p)->cb_masterFxIn(); }
+void geMainIO::cb_inToOut (Fl_Widget *v, void *p) { ((geMainIO*)p)->cb_inToOut(); }
#endif
/* -------------------------------------------------------------------------- */
-void geMainIO::__cb_outVol()
+void geMainIO::cb_outVol()
{
- glue_setOutVol(outVol->value());
+ c::main::setOutVol(outVol->value());
}
/* -------------------------------------------------------------------------- */
-void geMainIO::__cb_inVol()
+void geMainIO::cb_inVol()
{
- glue_setInVol(inVol->value());
+ c::main::setInVol(inVol->value());
}
#ifdef WITH_VST
-void geMainIO::__cb_masterFxOut()
+void geMainIO::cb_masterFxOut()
{
- gu_openSubWindow(G_MainWin, new gdPluginList(pluginHost::MASTER_OUT), WID_FX_LIST);
+ u::gui::openSubWindow(G_MainWin, new gdPluginList(m::pluginHost::StackType::MASTER_OUT), WID_FX_LIST);
}
-void geMainIO::__cb_masterFxIn()
+void geMainIO::cb_masterFxIn()
{
- gu_openSubWindow(G_MainWin, new gdPluginList(pluginHost::MASTER_IN), WID_FX_LIST);
+ u::gui::openSubWindow(G_MainWin, new gdPluginList(m::pluginHost::StackType::MASTER_IN), WID_FX_LIST);
}
-void geMainIO::__cb_inToOut()
+void geMainIO::cb_inToOut()
{
- mixer::inToOut = inToOut->value();
+ m::mixer::inToOut = inToOut->value();
}
#endif
void geMainIO::refresh()
{
- outMeter->mixerPeak = mixer::peakOut;
- inMeter->mixerPeak = mixer::peakIn;
+ outMeter->mixerPeak = m::mixer::peakOut.load();
+ inMeter->mixerPeak = m::mixer::peakIn.load();
outMeter->redraw();
inMeter->redraw();
}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class geButton;
#endif
+namespace giada {
+namespace v
+{
class geMainIO : public Fl_Group
{
private:
- geSoundMeter *outMeter;
- geSoundMeter *inMeter;
- geDial *outVol;
- geDial *inVol;
+ geSoundMeter* outMeter;
+ geSoundMeter* inMeter;
+ geDial* outVol;
+ geDial* inVol;
#ifdef WITH_VST
- geStatusButton *masterFxOut;
- geStatusButton *masterFxIn;
- geButton *inToOut;
+ geStatusButton* masterFxOut;
+ geStatusButton* masterFxIn;
+ geButton* inToOut;
#endif
- static void cb_outVol (Fl_Widget *v, void *p);
- static void cb_inVol (Fl_Widget *v, void *p);
+ static void cb_outVol (Fl_Widget* v, void* p);
+ static void cb_inVol (Fl_Widget* v, void* p);
#ifdef WITH_VST
- static void cb_masterFxOut(Fl_Widget *v, void *p);
- static void cb_masterFxIn (Fl_Widget *v, void *p);
- static void cb_inToOut (Fl_Widget *v, void *p);
+ static void cb_masterFxOut(Fl_Widget* v, void* p);
+ static void cb_masterFxIn (Fl_Widget* v, void* p);
+ static void cb_inToOut (Fl_Widget* v, void* p);
#endif
- inline void __cb_outVol ();
- inline void __cb_inVol ();
+ void cb_outVol ();
+ void cb_inVol ();
#ifdef WITH_VST
- inline void __cb_masterFxOut();
- inline void __cb_masterFxIn ();
- inline void __cb_inToOut ();
+ void cb_masterFxOut();
+ void cb_masterFxIn ();
+ void cb_inToOut ();
#endif
public:
void setMasterFxInFull(bool v);
#endif
};
+}} // giada::v::
+
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../glue/main.h"
#include "../../elems/basics/boxtypes.h"
#include "../../elems/basics/button.h"
-#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/mainWindow.h"
#include "../../dialogs/about.h"
-#include "../../dialogs/gd_config.h"
-#include "../../dialogs/gd_warnings.h"
+#include "../../dialogs/config.h"
+#include "../../dialogs/warnings.h"
#include "../../dialogs/browser/browserLoad.h"
#include "../../dialogs/browser/browserSave.h"
#include "../../dialogs/midiIO/midiInputMaster.h"
extern gdMainWindow* G_MainWin;
-using namespace giada::m;
-
-
+namespace giada {
+namespace v
+{
geMainMenu::geMainMenu(int x, int y)
: Fl_Group(x, y, 300, 20)
{
/* -------------------------------------------------------------------------- */
-void geMainMenu::cb_about (Fl_Widget* v, void* p) { ((geMainMenu*)p)->__cb_about(); }
-void geMainMenu::cb_config(Fl_Widget* v, void* p) { ((geMainMenu*)p)->__cb_config(); }
-void geMainMenu::cb_file (Fl_Widget* v, void* p) { ((geMainMenu*)p)->__cb_file(); }
-void geMainMenu::cb_edit (Fl_Widget* v, void* p) { ((geMainMenu*)p)->__cb_edit(); }
+void geMainMenu::cb_about (Fl_Widget* v, void* p) { ((geMainMenu*)p)->cb_about(); }
+void geMainMenu::cb_config(Fl_Widget* v, void* p) { ((geMainMenu*)p)->cb_config(); }
+void geMainMenu::cb_file (Fl_Widget* v, void* p) { ((geMainMenu*)p)->cb_file(); }
+void geMainMenu::cb_edit (Fl_Widget* v, void* p) { ((geMainMenu*)p)->cb_edit(); }
/* -------------------------------------------------------------------------- */
-void geMainMenu::__cb_about()
+void geMainMenu::cb_about()
{
- gu_openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT);
+ u::gui::openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT);
}
/* -------------------------------------------------------------------------- */
-void geMainMenu::__cb_config()
+void geMainMenu::cb_config()
{
- gu_openSubWindow(G_MainWin, new gdConfig(400, 370), WID_CONFIG);
+ u::gui::openSubWindow(G_MainWin, new gdConfig(400, 370), WID_CONFIG);
}
/* -------------------------------------------------------------------------- */
-void geMainMenu::__cb_file()
+void geMainMenu::cb_file()
{
+ using namespace giada::m;
+
/* An Fl_Menu_Button is made of many Fl_Menu_Item */
Fl_Menu_Item menu[] = {
if (!m) return;
if (strcmp(m->label(), "Open patch or project...") == 0) {
- gdWindow *childWin = new gdBrowserLoad(conf::browserX, conf::browserY,
+ gdWindow* childWin = new gdBrowserLoad(conf::browserX, conf::browserY,
conf::browserW, conf::browserH, "Load patch or project",
- conf::patchPath, glue_loadPatch, nullptr);
- gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
+ conf::patchPath, c::storage::loadPatch, nullptr);
+ u::gui::openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
return;
}
if (strcmp(m->label(), "Save patch...") == 0) {
return;
gdWindow *childWin = new gdBrowserSave(conf::browserX, conf::browserY,
conf::browserW, conf::browserH, "Save patch",
- conf::patchPath, patch::name, glue_savePatch, nullptr);
- gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
+ conf::patchPath, patch::name, c::storage::savePatch, nullptr);
+ u::gui::openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
return;
}
if (strcmp(m->label(), "Save project...") == 0) {
gdWindow *childWin = new gdBrowserSave(conf::browserX, conf::browserY,
conf::browserW, conf::browserH, "Save project",
- conf::patchPath, patch::name, glue_saveProject, nullptr);
- gu_openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
+ conf::patchPath, patch::name, c::storage::saveProject, nullptr);
+ u::gui::openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
return;
}
if (strcmp(m->label(), "Quit Giada") == 0) {
/* -------------------------------------------------------------------------- */
-void geMainMenu::__cb_edit()
+void geMainMenu::cb_edit()
{
Fl_Menu_Item menu[] = {
{"Clear all samples"},
menu[1].deactivate();
- for (const Channel* ch : mixer::channels)
+ for (const m::Channel* ch : m::mixer::channels)
if (ch->hasActions) {
menu[1].activate();
break;
}
- for (const Channel* ch : mixer::channels)
+ for (const m::Channel* ch : m::mixer::channels)
if (ch->hasData()) {
menu[0].activate();
break;
if (!gdConfirmWin("Warning", "Clear all samples: are you sure?"))
return;
G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
- glue_clearAllSamples();
+ c::main::clearAllSamples();
return;
}
if (strcmp(m->label(), "Clear all actions") == 0) {
if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
return;
G_MainWin->delSubWindow(WID_ACTION_EDITOR);
- glue_clearAllActions();
+ c::main::clearAllActions();
return;
}
if (strcmp(m->label(), "Reset to init state") == 0) {
if (!gdConfirmWin("Warning", "Reset to init state: are you sure?"))
return;
- glue_resetToInitState();
+ c::main::resetToInitState();
return;
}
if (strcmp(m->label(), "Remove empty columns") == 0) {
return;
}
if (strcmp(m->label(), "Setup global MIDI input...") == 0) {
- gu_openSubWindow(G_MainWin, new gdMidiInputMaster(), 0);
+ u::gui::openSubWindow(G_MainWin, new gdMidiInputMaster(), 0);
return;
}
}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class geButton;
+namespace giada {
+namespace v
+{
class geMainMenu : public Fl_Group
{
private:
- geButton *file;
- geButton *edit;
- geButton *config;
- geButton *about;
-
- static void cb_about (Fl_Widget *v, void *p);
- static void cb_config(Fl_Widget *v, void *p);
- static void cb_file (Fl_Widget *v, void *p);
- static void cb_edit (Fl_Widget *v, void *p);
+ geButton* file;
+ geButton* edit;
+ geButton* config;
+ geButton* about;
- inline void __cb_about ();
- inline void __cb_config();
- inline void __cb_file ();
- inline void __cb_edit ();
+ static void cb_about (Fl_Widget* v, void* p);
+ static void cb_config(Fl_Widget* v, void* p);
+ static void cb_file (Fl_Widget* v, void* p);
+ static void cb_edit (Fl_Widget* v, void* p);
+ void cb_about ();
+ void cb_config();
+ void cb_file ();
+ void cb_edit ();
public:
geMainMenu(int x, int y);
};
+}} // giada::v::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../utils/string.h"
#include "../../elems/basics/button.h"
#include "../../elems/basics/choice.h"
-#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/mainWindow.h"
#include "../../dialogs/bpmInput.h"
#include "../../dialogs/beatsInput.h"
#include "mainTimer.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
using std::string;
-using namespace giada::m;
+namespace giada {
+namespace v
+{
geMainTimer::geMainTimer(int x, int y)
- : Fl_Group(x, y, 180, 20)
+ : Fl_Group(x, y, 210, 20)
{
begin();
- quantizer = new geChoice(x, y, 40, 20, "", false);
- bpm = new geButton (quantizer->x()+quantizer->w()+4, y, 40, 20);
- meter = new geButton (bpm->x()+bpm->w()+8, y, 40, 20, "4/1");
- multiplier = new geButton (meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm);
- divider = new geButton (multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm);
+ quantizer = new geChoice(x, y, 50, 20, "", false);
+ bpm = new geButton(quantizer->x()+quantizer->w()+4, y, 50, 20);
+ meter = new geButton(bpm->x()+bpm->w()+8, y, 50, 20, "4/1");
+ multiplier = new geButton(meter->x()+meter->w()+4, y, 20, 20, "", multiplyOff_xpm, multiplyOn_xpm);
+ divider = new geButton(multiplier->x()+multiplier->w()+4, y, 20, 20, "", divideOff_xpm, divideOn_xpm);
end();
resizable(nullptr); // don't resize any widget
- bpm->copy_label(gu_fToString(clock::getBpm(), 1).c_str());
+ bpm->copy_label(u::string::fToString(m::clock::getBpm(), 1).c_str());
bpm->callback(cb_bpm, (void*)this);
meter->callback(cb_meter, (void*)this);
void geMainTimer::cb_bpm()
{
- gu_openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM);
+ u::gui::openSubWindow(G_MainWin, new gdBpmInput(bpm->label()), WID_BPM);
}
void geMainTimer::cb_meter()
{
- gu_openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS);
+ u::gui::openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS);
}
void geMainTimer::cb_quantizer()
{
- glue_quantize(quantizer->value());
+ c::main::quantize(quantizer->value());
}
void geMainTimer::cb_multiplier()
{
- glue_beatsMultiply();
+ c::main::beatsMultiply();
}
void geMainTimer::cb_divider()
{
- glue_beatsDivide();
+ c::main::beatsDivide();
}
void geMainTimer::setBpm(float v)
{
- bpm->copy_label(gu_fToString((float) v, 1).c_str()); // Only 1 decimal place (e.g. 120.0)
+ bpm->copy_label(u::string::fToString((float) v, 1).c_str()); // Only 1 decimal place (e.g. 120.0)
}
void geMainTimer::setMeter(int beats, int bars)
{
- string tmp = gu_iToString(beats) + "/" + gu_iToString(bars);
+ string tmp = u::string::iToString(beats) + "/" + u::string::iToString(bars);
meter->copy_label(tmp.c_str());
}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class geChoice;
+namespace giada {
+namespace v
+{
class geMainTimer : public Fl_Group
{
private:
void setLock(bool v);
};
+}} // giada::v::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../core/graphics.h"
+#include "../../../core/conf.h"
#include "../../../glue/transport.h"
#include "../../../glue/io.h"
#include "../../elems/basics/button.h"
#include "mainTransport.h"
-using namespace giada;
-
-
+namespace giada {
+namespace v
+{
geMainTransport::geMainTransport(int x, int y)
- : Fl_Group(x, y, 131, 25)
+ : Fl_Group(x, y, 174, 25)
{
begin();
- rewind = new geButton(x, y, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
- play = new geButton(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm);
- recAction = new geButton(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm);
- recInput = new geButton(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm);
- metronome = new geButton(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm);
+ rewind = new geButton(x, y, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
+ play = new geButton(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm);
+ recTriggerMode = new geButton(play->x()+play->w()+16, y+5, 15, 15, "", recTriggerModeOff_xpm, recTriggerModeOn_xpm);
+ recAction = new geButton(recTriggerMode->x()+recTriggerMode->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm);
+ recInput = new geButton(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm);
+ metronome = new geButton(recInput->x()+recInput->w()+16, y+5, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm);
end();
resizable(nullptr); // don't resize any widget
- rewind->callback(cb_rewind, (void*)this);
+ rewind->callback([](Fl_Widget* w, void* v) {
+ c::transport::rewindSeq(/*gui=*/true);
+ });
- play->callback(cb_play);
+ play->callback([](Fl_Widget* w, void* v) {
+ c::transport::startStopSeq(/*gui=*/true);
+ });
play->type(FL_TOGGLE_BUTTON);
- recAction->callback(cb_recAction, (void*)this);
+ recAction->callback([](Fl_Widget* w, void* v) {
+ c::io::toggleActionRec(/*gui=*/true);
+ });
recAction->type(FL_TOGGLE_BUTTON);
- recInput->callback(cb_recInput, (void*)this);
+ recInput->callback([](Fl_Widget* w, void* v) {
+ c::io::toggleInputRec(/*gui=*/true);
+ });
recInput->type(FL_TOGGLE_BUTTON);
- metronome->callback(cb_metronome);
- metronome->type(FL_TOGGLE_BUTTON);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-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()
-{
- c::transport::rewindSeq(true);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geMainTransport::cb_play()
-{
- c::transport::startStopSeq(true);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geMainTransport::cb_recAction()
-{
- using namespace giada::c::io;
- startStopActionRec(true);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geMainTransport::cb_recInput()
-{
- using namespace giada::c::io;
- startStopInputRec(true);
-}
-
+ recTriggerMode->value(m::conf::recTriggerMode);
+ recTriggerMode->type(FL_TOGGLE_BUTTON);
+ recTriggerMode->callback([](Fl_Widget* w, void* v) {
+ m::conf::recTriggerMode = static_cast<geButton*>(w)->value();
+ });
-/* -------------------------------------------------------------------------- */
-
-
-void geMainTransport::cb_metronome()
-{
- c::transport::startStopMetronome(true);
+ metronome->callback([](Fl_Widget* w, void* v) {
+ c::transport::toggleMetronome(/*gui=*/true);
+ });
+ metronome->type(FL_TOGGLE_BUTTON);
}
recAction->value(v);
recAction->redraw();
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geMainTransport::setRecTriggerModeActive(bool v)
+{
+ v ? recTriggerMode->activate() : recTriggerMode->deactivate();
+}
+
+}} // giada::v::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/Fl_Group.H>
+#include "../../../core/types.h"
class geButton;
+namespace giada {
+namespace v
+{
class geMainTransport : public Fl_Group
{
private:
- geButton *rewind;
- geButton *play;
- geButton *recAction;
- geButton *recInput;
- geButton *metronome;
+ geButton* rewind;
+ geButton* play;
+
+ geButton* recTriggerMode;
+ geButton* recAction;
+ geButton* recInput;
- static void cb_rewind (Fl_Widget *v, void *p);
- static void cb_play (Fl_Widget *v, void *p);
- 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);
- void cb_rewind ();
- void cb_play ();
- void cb_recAction();
- void cb_recInput ();
- void cb_metronome();
+ geButton* metronome;
public:
geMainTransport(int x, int y);
-
- void updatePlay (int v);
+
+ void updatePlay(int v);
void updateMetronome(int v);
- void updateRecInput (int v);
+ void updateRecInput(int v);
void updateRecAction(int v);
+ void setRecTriggerModeActive(bool v);
+
};
+}} // giada::v::
+
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
-using namespace giada::m;
+using namespace giada;
geMidiLearner::geMidiLearner(int X, int Y, int W, const char* l,
- midiDispatcher::cb_midiLearn* cb, uint32_t* param, Channel* ch)
- : Fl_Group(X, Y, W, 20),
- callback(cb),
- ch (ch),
- param (param)
+ m::midiDispatcher::cb_midiLearn* cb, uint32_t* param, m::Channel* ch)
+: Fl_Group(X, Y, W, 20),
+ callback(cb),
+ ch (ch),
+ param (param)
{
begin();
text = new geBox(x(), y(), 156, 20, l);
{
string tmp;
if (*param != 0x0) {
- tmp = "0x" + gu_iToString(*param, true); // true: hex mode
+ tmp = "0x" + u::string::iToString(*param, true); // true: hex mode
tmp.pop_back(); // Remove last two digits, useless in MIDI messages
tmp.pop_back(); // Remove last two digits, useless in MIDI messages
}
cbData.window = static_cast<gdMidiInputBase*>(parent()); // parent = gdMidiInput
cbData.learner = this;
cbData.channel = ch;
- midiDispatcher::startMidiLearn(callback, (void*)&cbData);
+ m::midiDispatcher::startMidiLearn(callback, (void*)&cbData);
}
else
- midiDispatcher::stopMidiLearn();
+ m::midiDispatcher::stopMidiLearn();
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/fl_draw.H>
#include "../../../core/plugin.h"
#include "../../../core/const.h"
+#include "../../../core/pluginManager.h"
#include "../../../core/pluginHost.h"
#include "../basics/boxtypes.h"
#include "pluginBrowser.h"
add("NAME\tMANUFACTURER\tCATEGORY\tFORMAT\tUID");
add("---\t---\t---\t---\t---");
- for (int i=0; i<pluginHost::countAvailablePlugins(); i++) {
- pluginHost::PluginInfo pi = pluginHost::getAvailablePluginInfo(i);
- string m = pluginHost::doesPluginExist(pi.uid) ? "" : "@-";
+ for (int i=0; i<pluginManager::countAvailablePlugins(); i++) {
+ pluginManager::PluginInfo pi = pluginManager::getAvailablePluginInfo(i);
+ string m = pluginManager::doesPluginExist(pi.uid) ? "" : "@-";
string s = m + pi.name + "\t" + m + pi.manufacturerName + "\t" + m +
pi.category + "\t" + m + pi.format + "\t" + m + pi.uid;
add(s.c_str());
}
- for (unsigned i=0; i<pluginHost::countUnknownPlugins(); i++) {
- string s = "?\t?\t?\t?\t? " + pluginHost::getUnknownPluginInfo(i) + " ?";
+ for (unsigned i=0; i<pluginManager::countUnknownPlugins(); i++) {
+ string s = "?\t?\t?\t?\t? " + pluginManager::getUnknownPluginInfo(i) + " ?";
add(s.c_str());
}
}
void gePluginBrowser::computeWidths()
{
int w0, w1, w3;
- for (int i=0; i<pluginHost::countAvailablePlugins(); i++) {
- pluginHost::PluginInfo pi = pluginHost::getAvailablePluginInfo(i);
+ for (int i=0; i<pluginManager::countAvailablePlugins(); i++) {
+ pluginManager::PluginInfo pi = pluginManager::getAvailablePluginInfo(i);
w0 = (int) fl_width(pi.name.c_str());
w1 = (int) fl_width(pi.manufacturerName.c_str());
w3 = (int) fl_width(pi.format.c_str());
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../utils/gui.h"
#include "../../../utils/log.h"
#include "../../../glue/plugin.h"
-#include "../../elems/basics/idButton.h"
+#include "../../elems/basics/button.h"
#include "../../elems/basics/choice.h"
-#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/mainWindow.h"
#include "../../dialogs/pluginList.h"
#include "../../dialogs/pluginWindowGUI.h"
#include "../../dialogs/pluginWindow.h"
m_plugin (p)
{
begin();
- button = new geIdButton(8, y(), 220, 20);
+ button = new geButton(8, y(), 220, 20);
program = new geChoice(button->x()+button->w()+4, y(), 132, 20);
- bypass = new geIdButton(program->x()+program->w()+4, y(), 20, 20);
- shiftUp = new geIdButton(bypass->x()+bypass->w()+4, y(), 20, 20, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm);
- shiftDown = new geIdButton(shiftUp->x()+shiftUp->w()+4, y(), 20, 20, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm);
- remove = new geIdButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm);
+ bypass = new geButton(program->x()+program->w()+4, y(), 20, 20);
+ shiftUp = new geButton(bypass->x()+bypass->w()+4, y(), 20, 20, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm);
+ shiftDown = new geButton(shiftUp->x()+shiftUp->w()+4, y(), 20, 20, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm);
+ remove = new geButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm);
end();
button->copy_label(m_plugin->getName().c_str());
program->callback(cb_setProgram, (void*)this);
for (int i=0; i<m_plugin->getNumPrograms(); i++)
- program->add(gu_removeFltkChars(m_plugin->getProgramName(i)).c_str());
+ program->add(u::gui::removeFltkChars(m_plugin->getProgramName(i)).c_str());
if (program->size() == 0) {
program->add("-- no programs --\0");
if (m::pluginHost::countPlugins(m_parentWin->stackType, m_parentWin->ch) == 1)
return;
- unsigned pluginIndex = m::pluginHost::getPluginIndex(m_plugin->getId(), m_parentWin->stackType, m_parentWin->ch);
- unsigned stackSize = (m::pluginHost::getStack(m_parentWin->stackType, m_parentWin->ch))->size();
+ int pluginIndex = m::pluginHost::getPluginIndex(m_plugin->getId(), m_parentWin->stackType, m_parentWin->ch);
+ int stackSize = m::pluginHost::getStack(m_parentWin->stackType, m_parentWin->ch).size();
if (pluginIndex == stackSize-1) // last one in the stack, do nothing
return;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class gdPluginList;
-class geIdButton;
class geChoice;
+class geButton;
class gePluginElement : public Fl_Group
public:
- geIdButton* button;
- geChoice* program;
- geIdButton* bypass;
- geIdButton* shiftUp;
- geIdButton* shiftDown;
- geIdButton* remove;
+ geButton* button;
+ geChoice* program;
+ geButton* bypass;
+ geButton* shiftUp;
+ geButton* shiftDown;
+ geButton* remove;
gePluginElement(gdPluginList* gdp, giada::m::Plugin* p, int x, int y, int w);
};
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
ch (ch)
{
begin();
- label = new geBox(x(), y(), gu_getStringWidth("Boost"), 20, "Boost", FL_ALIGN_RIGHT);
+ label = new geBox(x(), y(), u::gui::getStringWidth("Boost"), 20, "Boost", FL_ALIGN_RIGHT);
dial = new geDial(label->x()+label->w()+4, y(), 20, 20);
input = new geInput(dial->x()+dial->w()+4, y(), 70, 20);
normalize = new geButton(input->x()+input->w()+4, y(), 70, 20, "Normalize");
{
using namespace giada::u;
- input->value(gu_fToString(math::linearToDB(ch->getBoost()), 2).c_str()); // 2 digits
+ input->value(string::fToString(math::linearToDB(ch->getBoost()), 2).c_str()); // 2 digits
// A dial greater than it's max value goes crazy
dial->value(ch->getBoost() <= 10.0f ? ch->getBoost() : 10.0f);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
ch (ch)
{
begin();
- label = new geBox(x, y, gu_getStringWidth("Pan"), 20, "Pan", FL_ALIGN_RIGHT);
+ label = new geBox(x, y, u::gui::getStringWidth("Pan"), 20, "Pan", FL_ALIGN_RIGHT);
dial = new geDial(label->x()+label->w()+4, y, 20, 20);
input = new geInput(dial->x()+dial->w()+4, y, 70, 20);
reset = new geButton(input->x()+input->w()+4, y, 70, 20, "Reset");
dial->value(ch->getPan());
if (ch->getPan() < 0.5f) {
- string tmp = gu_iToString((int) ((-ch->getPan() * 200.0f) + 100.0f)) + " L";
+ string tmp = u::string::iToString((int) ((-ch->getPan() * 200.0f) + 100.0f)) + " L";
input->value(tmp.c_str());
}
else
if (ch->getPan() == 0.5)
input->value("C");
else {
- string tmp = gu_iToString((int) ((ch->getPan() * 200.0f) - 100.0f)) + " R";
+ string tmp = u::string::iToString((int) ((ch->getPan() * 200.0f) - 100.0f)) + " R";
input->value(tmp.c_str());
}
}
/* -------------------------------------------------------------------------- */
-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(); }
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
ch (ch)
{
begin();
- label = new geBox(x, y, gu_getStringWidth("Pitch"), 20, "Pitch", FL_ALIGN_RIGHT);
+ label = new geBox(x, y, u::gui::getStringWidth("Pitch"), 20, "Pitch", FL_ALIGN_RIGHT);
dial = new geDial(label->x()+label->w()+4, y, 20, 20);
input = new geInput(dial->x()+dial->w()+4, y, 70, 20);
pitchToBar = new geButton(input->x()+input->w()+4, y, 70, 20, "To bar");
void gePitchTool::refresh()
{
dial->value(ch->getPitch());
- input->value(gu_fToString(ch->getPitch(), 4).c_str()); // 4 digits
+ input->value(u::string::fToString(ch->getPitch(), 4).c_str()); // 4 digits
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "rangeTool.h"
-using namespace giada::c;
+using namespace giada;
geRangeTool::geRangeTool(int x, int y, giada::m::SampleChannel* ch)
m_ch (ch)
{
begin();
- m_label = new geBox(x, y, gu_getStringWidth("Range"), G_GUI_UNIT, "Range", FL_ALIGN_RIGHT);
+ m_label = new geBox(x, y, u::gui::getStringWidth("Range"), G_GUI_UNIT, "Range", FL_ALIGN_RIGHT);
m_begin = new geInput(m_label->x()+m_label->w()+G_GUI_INNER_MARGIN, y, 70, G_GUI_UNIT);
m_end = new geInput(m_begin->x()+m_begin->w()+G_GUI_INNER_MARGIN, y, 70, G_GUI_UNIT);
m_reset = new geButton(m_end->x()+m_end->w()+G_GUI_INNER_MARGIN, y, 70, G_GUI_UNIT, "Reset");
void geRangeTool::refresh()
{
- m_begin->value(gu_iToString(m_ch->getBegin()).c_str());
- m_end->value(gu_iToString(m_ch->getEnd()).c_str());
+ m_begin->value(u::string::iToString(m_ch->getBegin()).c_str());
+ m_end->value(u::string::iToString(m_ch->getEnd()).c_str());
}
void geRangeTool::cb_setChanPos()
{
- sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
+ c::sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform(); // TODO - glue's business!
}
void geRangeTool::cb_resetStartEnd()
{
- sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
+ c::sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform(); // TODO - glue's business!
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../../utils/gui.h"
#include "../../../utils/string.h"
#include "../../../glue/sampleEditor.h"
-#include "../../dialogs/gd_warnings.h"
+#include "../../dialogs/warnings.h"
#include "../basics/input.h"
#include "../basics/box.h"
#include "../basics/button.h"
#include "shiftTool.h"
-using namespace giada::c;
+using namespace giada;
geShiftTool::geShiftTool(int x, int y, giada::m::SampleChannel* ch)
m_ch (ch)
{
begin();
- m_label = new geBox(x, y, gu_getStringWidth("Shift"), G_GUI_UNIT, "Shift", FL_ALIGN_RIGHT);
+ m_label = new geBox(x, y, u::gui::getStringWidth("Shift"), G_GUI_UNIT, "Shift", FL_ALIGN_RIGHT);
m_shift = new geInput(m_label->x()+m_label->w()+G_GUI_INNER_MARGIN, y, 70, G_GUI_UNIT);
m_reset = new geButton(m_shift->x()+m_shift->w()+G_GUI_INNER_MARGIN, y, 70, G_GUI_UNIT, "Reset");
end();
m_shift->type(FL_INT_INPUT);
m_shift->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
- m_shift->value(gu_iToString(ch->shift).c_str());
+ m_shift->value(u::string::iToString(ch->shift).c_str());
m_shift->callback(cb_setShift, (void*)this);
m_reset->callback(cb_reset, (void*)this);
void geShiftTool::refresh()
{
- m_shift->value(gu_iToString(m_ch->shift).c_str());
+ m_shift->value(u::string::iToString(m_ch->shift).c_str());
}
if (m_ch->isPlaying())
gdAlert("Can't shift sample while playing.");
else
- sampleEditor::shift(m_ch, f);
+ c::sampleEditor::shift(m_ch, f);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
ch (ch)
{
begin();
- label = new geBox (x(), y(), gu_getStringWidth("Volume"), 20, "Volume", FL_ALIGN_RIGHT);
+ label = new geBox (x(), y(), u::gui::getStringWidth("Volume"), 20, "Volume", FL_ALIGN_RIGHT);
dial = new geDial (label->x()+label->w()+4, y(), 20, 20);
input = new geInput(dial->x()+dial->w()+4, y(), 70, 20);
end();
void geVolumeTool::refresh()
{
- using namespace giada::u;
-
string tmp;
- float dB = math::linearToDB(ch->volume);
- if (dB > -INFINITY) tmp = gu_fToString(dB, 2); // 2 digits
+ float dB = u::math::linearToDB(ch->volume);
+ if (dB > -INFINITY) tmp = u::string::fToString(dB, 2); // 2 digits
else tmp = "-inf";
input->value(tmp.c_str());
dial->value(ch->guiChannel->vol->value());
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
int geWaveform::alloc(int datasize, bool force)
{
- Wave* wave = m_ch->wave;
+ const Wave* wave = m_ch->wave.get();
m_ratio = wave->getSize() / (float) datasize;
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <FL/fl_draw.H>
#include "../../core/const.h"
#include "../../core/kernelAudio.h"
+#include "../../utils/math.h"
#include "soundMeter.h"
-using namespace giada::m;
+using namespace giada;
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)
+: Fl_Box (x, y, w, h, l),
+ mixerPeak (0.0f),
+ m_dbLevelCur(0.0f),
+ m_dbLevelOld(0.0f)
{
}
{
fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);
- /* peak = the highest value inside the frame */
+ /* Compute peak level on 0.0 -> 1.0 scale. 1.0 is considered clip. */
- peak = 0.0f;
- float tmp_peak = 0.0f;
+ bool clip = std::fabs(mixerPeak) >= 1.0f ? true : false;
- tmp_peak = fabs(mixerPeak);
- if (tmp_peak > peak)
- peak = tmp_peak;
+ /* dBFS (full scale) calculation, plus decay of -2dB per frame. */
- clip = peak >= 1.0f ? true : false; // 1.0f is considered clip
+ m_dbLevelCur = u::math::linearToDB(std::fabs(mixerPeak));
+ if (m_dbLevelCur < m_dbLevelOld && m_dbLevelOld > -G_MIN_DB_SCALE)
+ m_dbLevelCur = m_dbLevelOld - 2.0f;
- /* dBFS (full scale) calculation, plus decay of -2dB per frame */
+ m_dbLevelOld = m_dbLevelCur;
- dbLevel = 20 * log10(peak);
- if (dbLevel < dbLevelOld)
- if (dbLevelOld > -G_MIN_DB_SCALE)
- dbLevel = dbLevelOld - 2.0f;
+ /* Paint the meter on screen. */
- dbLevelOld = dbLevel;
-
- /* 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 pxLevel = ((w()/G_MIN_DB_SCALE) * m_dbLevelCur) + 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, (int) pxLevel, h()-2, clip || !m::kernelAudio::getStatus() ? G_COLOR_RED_ALERT : G_COLOR_GREY_4);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
void draw() override;
- bool clip;
- float mixerPeak; // peak from mixer
+ float mixerPeak; // peak from mixer
private:
- float peak;
- float dbLevel;
- float dbLevelOld;
+ float m_dbLevelCur;
+ float m_dbLevelOld;
};
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
using std::string;
using std::vector;
+using namespace giada;
bool gu_fileExists(const string &filename)
string gu_stripFileUrl(const string& f)
{
string out = f;
- out = gu_replace(out, "file://", "");
- out = gu_replace(out, "%20", " ");
+ out = u::string::replace(out, "file://", "");
+ out = u::string::replace(out, "%20", " ");
return out;
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../core/channel.h"
#include "../core/conf.h"
#include "../core/graphics.h"
-#include "../gui/dialogs/gd_warnings.h"
-#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/warnings.h"
+#include "../gui/dialogs/mainWindow.h"
#include "../gui/dialogs/actionEditor/baseActionEditor.h"
#include "../gui/dialogs/window.h"
#include "../gui/dialogs/sampleEditor.h"
extern gdMainWindow* G_MainWin;
-using std::string;
-using namespace giada;
-using namespace giada::m;
-using namespace giada::v;
+namespace giada {
+namespace u {
+namespace gui
+{
+namespace
+{
+int blinker_ = 0;
+} // {anonymous}
-static int blinker = 0;
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
-void gu_refreshUI()
+void refreshUI()
{
Fl::lock();
/* compute timer for blinker */
- blinker++;
- if (blinker > 12)
- blinker = 0;
+ if (blinker_++ > 12)
+ blinker_ = 0;
/* If Sample Editor is open, repaint it (for dynamic play head). */
- gdSampleEditor* se = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* se = static_cast<gdSampleEditor*>(getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (se != nullptr)
se->waveTools->redrawWaveformAsync();
/* -------------------------------------------------------------------------- */
-int gu_getBlinker()
+bool shouldBlink()
{
- return blinker;
+ return blinker_ > 6;
}
/* -------------------------------------------------------------------------- */
-void gu_updateControls()
+void updateControls()
{
+ using namespace giada::m;
+
for (const Channel* ch : mixer::channels)
ch->guiChannel->update();
- G_MainWin->mainIO->setOutVol(mixer::outVol);
- G_MainWin->mainIO->setInVol(mixer::inVol);
+ G_MainWin->mainIO->setOutVol(mixer::outVol.load());
+ G_MainWin->mainIO->setInVol(mixer::inVol.load());
+
#ifdef WITH_VST
- G_MainWin->mainIO->setMasterFxOutFull(pluginHost::getStack(pluginHost::MASTER_OUT)->size() > 0);
- G_MainWin->mainIO->setMasterFxInFull(pluginHost::getStack(pluginHost::MASTER_IN)->size() > 0);
+
+ G_MainWin->mainIO->setMasterFxOutFull(pluginHost::getStack(pluginHost::StackType::MASTER_OUT).size() > 0);
+ G_MainWin->mainIO->setMasterFxInFull(pluginHost::getStack(pluginHost::StackType::MASTER_IN).size() > 0);
+
#endif
G_MainWin->mainTimer->setMeter(clock::getBeats(), clock::getBars());
G_MainWin->mainTimer->setQuantizer(clock::getQuantize());
G_MainWin->mainTransport->updatePlay(clock::isRunning());
- G_MainWin->mainTransport->updateMetronome(mixer::metronome);
+ G_MainWin->mainTransport->updateMetronome(mixer::isMetronomeOn());
}
/* -------------------------------------------------------------------------- */
-void gu_updateMainWinLabel(const string& s)
+void updateMainWinLabel(const std::string& s)
{
std::string out = std::string(G_APP_NAME) + " - " + s;
G_MainWin->copy_label(out.c_str());
/* -------------------------------------------------------------------------- */
-void gu_setFavicon(Fl_Window* w)
+void setFavicon(Fl_Window* w)
{
#if defined(__linux__)
/* -------------------------------------------------------------------------- */
-void gu_openSubWindow(gdWindow* parent, gdWindow* child, int id)
+void openSubWindow(gdWindow* parent, gdWindow* child, int id)
{
if (parent->hasWindow(id)) {
gu_log("[GU] parent has subwindow with id=%d, deleting\n", id);
/* -------------------------------------------------------------------------- */
-void gu_refreshActionEditor()
+void refreshActionEditor()
{
- gdBaseActionEditor* ae = static_cast<gdBaseActionEditor*>(G_MainWin->getChild(WID_ACTION_EDITOR));
+ v::gdBaseActionEditor* ae = static_cast<v::gdBaseActionEditor*>(G_MainWin->getChild(WID_ACTION_EDITOR));
if (ae != nullptr)
ae->rebuild();
}
/* -------------------------------------------------------------------------- */
-gdWindow* gu_getSubwindow(gdWindow* parent, int id)
+gdWindow* getSubwindow(gdWindow* parent, int id)
{
if (parent->hasWindow(id))
return parent->getChild(id);
/* -------------------------------------------------------------------------- */
-void gu_closeAllSubwindows()
+void closeAllSubwindows()
{
/* don't close WID_FILE_BROWSER, because it's the caller of this
* function */
/* -------------------------------------------------------------------------- */
-int gu_getStringWidth(const std::string& s)
+int getStringWidth(const std::string& s)
{
int w = 0;
int h = 0;
/* -------------------------------------------------------------------------- */
-string gu_removeFltkChars(const string& s)
+std::string removeFltkChars(const std::string& s)
{
- string out = gu_replace(s, "/", "-");
- out = gu_replace(out, "|", "-");
- out = gu_replace(out, "&", "-");
- out = gu_replace(out, "_", "-");
+ std::string out = u::string::replace(s, "/", "-");
+ out = u::string::replace(out, "|", "-");
+ out = u::string::replace(out, "&", "-");
+ out = u::string::replace(out, "_", "-");
return out;
}
+
+}}} // giada::u::gui::
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
class gdWindow;
+namespace giada {
+namespace u {
+namespace gui
+{
/* refresh
- * refresh all GUI elements. */
+Repaints some dynamic GUI elements. */
-void gu_refreshUI();
+void refreshUI();
-/* getBlinker
-* return blinker value, used to make widgets blink. */
+/* shouldBlink
+Return whether is time to blink something or not. This is used to make widgets
+blink. */
-int gu_getBlinker();
+bool shouldBlink();
/* updateControls
- * update attributes of control elements (sample names, volumes, ...).
- * Useful when loading a new patch. */
+Updates attributes of control elements (sample names, volumes, ...). Useful when
+loading a new patch. */
-void gu_updateControls();
+void updateControls();
-/* update_win_label
- * update the name of the main window */
+/* updateMainWinLabel
+Updates the name of the main window */
-void gu_updateMainWinLabel(const std::string &s);
+void updateMainWinLabel(const std::string& s);
-void gu_setFavicon(Fl_Window *w);
+void setFavicon(Fl_Window* w);
-void gu_openSubWindow(gdWindow *parent, gdWindow *child, int id);
+void openSubWindow(gdWindow* parent, gdWindow* child, int id);
/* refreshActionEditor
- * reload the action editor window by closing and reopening it. It's used
- * when you delete some actions from the mainWindow and the action editor
- * window is open. */
+Reloads the action editor window by closing and reopening it. It's used when you
+delete some actions from the mainWindow and the action editor window is open. */
-void gu_refreshActionEditor();
+void refreshActionEditor();
/* closeAllSubwindows
- * close all subwindows attached to mainWin. */
+Closes all subwindows attached to mainWin. */
-void gu_closeAllSubwindows();
+void closeAllSubwindows();
/* getSubwindow
- * return a pointer to an open subwindow, otherwise nullptr. */
+Returns a pointer to an open subwindow, otherwise nullptr. */
-gdWindow *gu_getSubwindow(gdWindow *parent, int id);
+gdWindow* getSubwindow(gdWindow* parent, int id);
/* removeFltkChars
- * Strip special chars used by FLTK to split menus into sub-menus. */
+Strips special chars used by FLTK to split menus into sub-menus. */
-std::string gu_removeFltkChars(const std::string &s);
+std::string removeFltkChars(const std::string& s);
-int gu_getStringWidth(const std::string &s);
+int getStringWidth(const std::string& s);
+
+}}} // giada::u::gui::
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
{
/* Source:
https://en.wikipedia.org/wiki/Quantization_(signal_processing)#Rounding_example */
- return step * floor((x / (float) step) + 0.5f);
+ return step * std::floor((x / (float) step) + 0.5f);
}
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "string.h"
-using std::string;
-using std::vector;
-
-
-string gu_getRealPath(const string& path)
+namespace giada {
+namespace u {
+namespace string
{
- string out = "";
+std::string getRealPath(const std::string& path)
+{
+ std::string out = "";
#if defined(G_OS_LINUX) || defined(G_OS_MAC)
/* TODO - use std::to_string() */
-string gu_fToString(float f, int precision)
+std::string fToString(float f, int precision)
{
std::stringstream out;
out << std::fixed << std::setprecision(precision) << f;
/* -------------------------------------------------------------------------- */
-string gu_trim(const string& s)
+std::string trim(const std::string& s)
{
std::size_t first = s.find_first_not_of(" \n\t");
std::size_t last = s.find_last_not_of(" \n\t");
/* -------------------------------------------------------------------------- */
-string gu_replace(string in, const string& search, const string& replace)
+std::string replace(std::string in, const std::string& search, const std::string& replace)
{
size_t pos = 0;
- while ((pos = in.find(search, pos)) != string::npos) {
+ while ((pos = in.find(search, pos)) != std::string::npos) {
in.replace(pos, search.length(), replace);
pos += replace.length();
}
/* -------------------------------------------------------------------------- */
-std::string gu_format(const char* format, ...)
+std::string format(const char* format, ...)
{
va_list args;
- /* Compute the size of the new expanded string (i.e. with replacement taken
+ /* Compute the size of the new expanded std::string (i.e. with replacement taken
into account). */
va_start(args, format);
size_t size = vsnprintf(nullptr, 0, format, args) + 1;
va_end(args);
- /* Create a new temporary char array to hold the new expanded string. */
+ /* Create a new temporary char array to hold the new expanded std::string. */
std::unique_ptr<char[]> tmp(new char[size]);
- /* Fill the temporary string with the formatted data. */
+ /* Fill the temporary std::string with the formatted data. */
- va_start(args, format);
+ va_start(args, format);
vsprintf(tmp.get(), format, args);
- va_end(args);
-
- return string(tmp.get(), tmp.get() + size - 1);
+ va_end(args);
+
+ return std::string(tmp.get(), tmp.get() + size - 1);
}
/* -------------------------------------------------------------------------- */
-void gu_split(string in, string sep, vector<string>* v)
+std::vector<std::string> split(std::string in, std::string sep)
{
- string full = in;
- string token = "";
+ std::vector<std::string> out;
+ std::string full = in;
+ std::string token = "";
size_t curr = 0;
size_t next = -1;
do {
next = full.find_first_of(sep, curr);
token = full.substr(curr, next - curr);
if (token != "")
- v->push_back(token);
+ out.push_back(token);
}
- while (next != string::npos);
+ while (next != std::string::npos);
+ return out;
}
+
+}}} // giada::u::string
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include <string>
#include <vector>
#include <sstream>
-#include "../core/const.h"
+namespace giada {
+namespace u {
+namespace string
+{
template <typename T>
-std::string gu_iToString(T t, bool hex=false)
+std::string iToString(T t, bool hex=false)
{
std::stringstream out;
if (hex)
return out.str();
}
-std::string gu_getRealPath(const std::string& path);
+std::string getRealPath(const std::string& path);
-std::string gu_replace(std::string in, const std::string& search,
+std::string replace(std::string in, const std::string& search,
const std::string& replace);
-std::string gu_trim(const std::string& s);
+std::string trim(const std::string& s);
-void gu_split(std::string in, std::string sep, std::vector<std::string>* v);
+std::vector<std::string> split(std::string in, std::string sep);
-std::string gu_fToString(float f, int precision);
+std::string fToString(float f, int precision);
-std::string gu_format(const char* format, ...);
+std::string format(const char* format, ...);
+}}} // giada::u::string
#endif
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2019 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_UTILS_VECTOR_H
+#define G_UTILS_VECTOR_H
+
+
+#include <vector>
+#include <algorithm>
+#include <functional>
+
+
+namespace giada {
+namespace u {
+namespace vector
+{
+template <typename T>
+int indexOf(std::vector<T>& v, T obj)
+{
+ auto it = std::find(v.begin(), v.end(), obj);
+ return it != v.end() ? std::distance(v.begin(), it) : -1;
+}
+
+
+template <typename T, typename F>
+int indexOf(std::vector<T>& v, F&& func)
+{
+ auto it = std::find_if(v.begin(), v.end(), func);
+ return it != v.end() ? std::distance(v.begin(), it) : -1;
+}
+}}}; // giada::u::vector::
+
+#endif
\ No newline at end of file
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2019 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
conf::channelsIn = 6;
conf::samplerate = 7;
conf::buffersize = 8;
- conf::delayComp = 9;
conf::limitOutput = true;
conf::rsmpQuality = 10;
conf::midiSystem = 11;
REQUIRE(conf::channelsIn == 6);
REQUIRE(conf::samplerate == 44100); // sanitized
REQUIRE(conf::buffersize == 8);
- REQUIRE(conf::delayComp == 9);
REQUIRE(conf::limitOutput == true);
REQUIRE(conf::rsmpQuality == 0); // sanitized
REQUIRE(conf::midiSystem == 11);
channel1.begin = 0;
channel1.end = 0;
channel1.boost = 0;
- channel1.recActive = 0;
+ channel1.readActions = 0;
channel1.pitch = 1.2f;
channel1.midiInReadActions = 0;
channel1.midiInPitch = 0;
REQUIRE(channel0.begin == 0);
REQUIRE(channel0.end == 0);
REQUIRE(channel0.boost == 1.0f);
- REQUIRE(channel0.recActive == 0);
+ REQUIRE(channel0.readActions == 0);
REQUIRE(channel0.pitch == Approx(1.2f));
REQUIRE(channel0.midiInReadActions == 0);
REQUIRE(channel0.midiInPitch == 0);
ChannelMode::SINGLE_ENDLESS };
SampleChannel ch(false, BUFFER_SIZE);
- Wave* w;
- waveManager::create("tests/resources/test.wav", &w);
- ch.pushWave(w);
+ waveManager::Result res = waveManager::createFromFile("tests/resources/test.wav");
+ int waveSize = res.wave->getSize();
+ ch.pushWave(std::move(res.wave));
SECTION("push wave")
{
REQUIRE(ch.status == ChannelStatus::OFF);
- REQUIRE(ch.wave == w);
REQUIRE(ch.begin == 0);
- REQUIRE(ch.end == w->getSize() - 1);
+ REQUIRE(ch.end == waveSize - 1);
REQUIRE(ch.name == "");
}
ch.setBegin(100000);
- REQUIRE(ch.getBegin() == w->getSize());
- REQUIRE(ch.tracker == w->getSize());
- REQUIRE(ch.trackerPreview == w->getSize());
+ REQUIRE(ch.getBegin() == waveSize);
+ REQUIRE(ch.tracker == waveSize);
+ REQUIRE(ch.trackerPreview == waveSize);
ch.setBegin(16);
ch.setEnd(100000);
- REQUIRE(ch.getEnd() == w->getSize() - 1);
+ REQUIRE(ch.getEnd() == waveSize - 1);
ch.setEnd(32);
ChannelMode::SINGLE_PRESS, ChannelMode::SINGLE_RETRIG,
ChannelMode::SINGLE_ENDLESS };
- Wave* w;
SampleChannel ch(false, BUFFER_SIZE);
- waveManager::create("tests/resources/test.wav", &w);
+ waveManager::Result res = waveManager::createFromFile("tests/resources/test.wav");
REQUIRE(ch.status == ChannelStatus::EMPTY);
REQUIRE(ch.mode == ChannelMode::SINGLE_BASIC);
REQUIRE(ch.tracker == 0);
/* With data, stopped. */
- ch.pushWave(w);
+ ch.pushWave(std::move(res.wave));
sampleChannelProc::prepareBuffer(&ch, /*running=*/false);
REQUIRE(ch.tracker == 0);
SECTION("fill")
{
- ch.pushWave(w);
+ ch.pushWave(std::move(res.wave));
/* Zero offset. */
REQUIRE(ch.fillBuffer(ch.buffer, 0, 0) == BUFFER_SIZE);
SECTION("statuses")
{
- ch.pushWave(w);
+ ch.pushWave(std::move(res.wave));
SECTION("start from OFF")
{
REQUIRE(ch.status == ChannelStatus::WAIT);
else {
REQUIRE(ch.status == ChannelStatus::OFF);
- REQUIRE(ch.qWait == true);
+ REQUIRE(ch.quantizing == true);
}
}
}
SECTION("rewind by sequencer")
{
- ch.pushWave(w);
+ ch.pushWave(std::move(res.wave));
/* Test loop modes. */
TEST_CASE("u::string")
{
using std::vector;
+ using namespace giada::u::string;
- REQUIRE(gu_replace("Giada is cool", "cool", "hot") == "Giada is hot");
- REQUIRE(gu_trim(" Giada is cool ") == "Giada is cool");
- REQUIRE(gu_iToString(666) == "666");
- REQUIRE(gu_iToString(0x99AABB, true) == "99AABB");
- REQUIRE(gu_fToString(3.14159, 2) == "3.14");
- REQUIRE(gu_format("I see %d men with %s hats", 5, "strange") == "I see 5 men with strange hats");
+ REQUIRE(replace("Giada is cool", "cool", "hot") == "Giada is hot");
+ REQUIRE(trim(" Giada is cool ") == "Giada is cool");
+ REQUIRE(iToString(666) == "666");
+ REQUIRE(iToString(0x99AABB, true) == "99AABB");
+ REQUIRE(fToString(3.14159, 2) == "3.14");
+ REQUIRE(format("I see %d men with %s hats", 5, "strange") == "I see 5 men with strange hats");
- vector<std::string> v;
- gu_split("Giada is cool", " ", &v);
+ vector<std::string> v = split("Giada is cool", " ");
REQUIRE(v.size() == 3);
REQUIRE(v.at(0) == "Giada");
REQUIRE(v.at(1) == "is");
TEST_CASE("waveManager")
{
- /* Each SECTION the TEST_CASE is executed from the start. Any code between
- this comment and the first SECTION macro is exectuted before each SECTION. */
-
- Wave* w;
-
- SECTION("test creation")
- {
- int res = waveManager::create("tests/resources/test.wav", &w);
- std::unique_ptr<Wave> wave(w);
-
- REQUIRE(res == G_RES_OK);
- REQUIRE(wave->getRate() == G_SAMPLE_RATE);
- REQUIRE(wave->getChannels() == G_CHANNELS);
- REQUIRE(wave->isLogical() == false);
- REQUIRE(wave->isEdited() == false);
- }
-
- SECTION("test recording")
- {
- waveManager::createEmpty(G_BUFFER_SIZE, G_MAX_IO_CHANS, G_SAMPLE_RATE,
- "test.wav", &w);
- std::unique_ptr<Wave> wave(w);
-
- REQUIRE(wave->getRate() == G_SAMPLE_RATE);
- REQUIRE(wave->getSize() == G_BUFFER_SIZE);
- REQUIRE(wave->getChannels() == G_CHANNELS);
- REQUIRE(wave->isLogical() == true);
- REQUIRE(wave->isEdited() == false);
- }
-
- SECTION("test resampling")
- {
- waveManager::create("tests/resources/test.wav", &w);
- std::unique_ptr<Wave> wave(w);
-
- int oldSize = wave->getSize();
- waveManager::resample(wave.get(), 1, G_SAMPLE_RATE * 2);
-
- REQUIRE(wave->getRate() == G_SAMPLE_RATE * 2);
- REQUIRE(wave->getSize() == oldSize * 2);
- REQUIRE(wave->getChannels() == G_CHANNELS);
- REQUIRE(wave->isLogical() == false);
- REQUIRE(wave->isEdited() == false);
- }
+ /* Each SECTION the TEST_CASE is executed from the start. Any code between
+ this comment and the first SECTION macro is exectuted before each SECTION. */
+
+ SECTION("test creation")
+ {
+ waveManager::Result res = waveManager::createFromFile("tests/resources/test.wav");
+
+ REQUIRE(res.status == G_RES_OK);
+ REQUIRE(res.wave->getRate() == G_SAMPLE_RATE);
+ REQUIRE(res.wave->getChannels() == G_CHANNELS);
+ REQUIRE(res.wave->isLogical() == false);
+ REQUIRE(res.wave->isEdited() == false);
+ }
+
+ SECTION("test recording")
+ {
+ std::unique_ptr<Wave> wave = waveManager::createEmpty(G_BUFFER_SIZE,
+ G_MAX_IO_CHANS, G_SAMPLE_RATE, "test.wav");
+
+ REQUIRE(wave->getRate() == G_SAMPLE_RATE);
+ REQUIRE(wave->getSize() == G_BUFFER_SIZE);
+ REQUIRE(wave->getChannels() == G_CHANNELS);
+ REQUIRE(wave->isLogical() == true);
+ REQUIRE(wave->isEdited() == false);
+ }
+
+ SECTION("test resampling")
+ {
+ waveManager::Result res = waveManager::createFromFile("tests/resources/test.wav");
+
+ int oldSize = res.wave->getSize();
+ waveManager::resample(res.wave.get(), 1, G_SAMPLE_RATE * 2);
+
+ REQUIRE(res.wave->getRate() == G_SAMPLE_RATE * 2);
+ REQUIRE(res.wave->getSize() == oldSize * 2);
+ REQUIRE(res.wave->getChannels() == G_CHANNELS);
+ REQUIRE(res.wave->isLogical() == false);
+ REQUIRE(res.wave->isEdited() == false);
+ }
}