--------------------------------------------------------------------------------
+0.14.4 --- 2017 . 10 . 28
+- Renameable channels
+- Portable VST path
+- [Sample Editor] Sample shift tool
+- [Linux/Mac] Don't skip '/' path when navigating to upper folders
+- Ability to process more than one plug-in instrument at once
+- Beautify Configuration Window
+- Bring VST window to front when opening UI
+- Save 'arm' status to patch/project file
+- Revamped Beats and Bpm input windows
+- Simplified audio samples' storage in project folders
+- Update JUCE to version 5.1.2
+- UI-less plug-in window refinements
+- Update UI-less plug-in window on MIDI parameter's change
+- Strip .gptc/.gprj extention from patch name
+- [Sample Editor] Fix non-working 'cut' operation
+- Fix missed MIDI events with more than 1 plug-in in the stack
+- Fix File Browser path widget drawn incorrectly in OS X
+- Fix missing MIDI learn for 'Arm channel' and 'Kill channel'
+
+
0.14.3 --- 2017 . 09 . 18
- [Sample Editor] New "reverse selection" function
- [Sample Editor] New "normalize hard" function
- [Sample Editor] New "copy to channel" function
+- [Sample Editor] New "copy & paste" function
- [Sample Editor] Double click on waveform selects all
- [Sample Editor] Fix garbled characters in window's title
- [Sample Editor] Fix wrong result on "set pitch to song/bar"
src/gui/dialogs/gd_about.cpp \
src/gui/dialogs/gd_mainWindow.h \
src/gui/dialogs/gd_mainWindow.cpp \
-src/gui/dialogs/gd_beatsInput.h \
-src/gui/dialogs/gd_beatsInput.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/gd_bpmInput.h \
-src/gui/dialogs/gd_bpmInput.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/gd_pluginList.h \
-src/gui/dialogs/gd_pluginList.cpp \
-src/gui/dialogs/gd_pluginWindow.h \
-src/gui/dialogs/gd_pluginWindow.cpp \
+src/gui/dialogs/pluginList.h \
+src/gui/dialogs/pluginList.cpp \
+src/gui/dialogs/pluginWindow.h \
+src/gui/dialogs/pluginWindow.cpp \
src/gui/dialogs/sampleEditor.h \
src/gui/dialogs/sampleEditor.cpp \
-src/gui/dialogs/gd_pluginWindowGUI.h \
-src/gui/dialogs/gd_pluginWindowGUI.cpp \
+src/gui/dialogs/pluginWindowGUI.h \
+src/gui/dialogs/pluginWindowGUI.cpp \
src/gui/dialogs/gd_actionEditor.h \
src/gui/dialogs/gd_actionEditor.cpp \
-src/gui/dialogs/gd_pluginChooser.h \
-src/gui/dialogs/gd_pluginChooser.cpp \
+src/gui/dialogs/pluginChooser.h \
+src/gui/dialogs/pluginChooser.cpp \
src/gui/dialogs/browser/browserBase.h \
src/gui/dialogs/browser/browserBase.cpp \
src/gui/dialogs/browser/browserLoad.h \
src/gui/elems/browser.cpp \
src/gui/elems/soundMeter.h \
src/gui/elems/soundMeter.cpp \
-src/gui/elems/pluginBrowser.h \
-src/gui/elems/pluginBrowser.cpp \
+src/gui/elems/plugin/pluginBrowser.h \
+src/gui/elems/plugin/pluginBrowser.cpp \
+src/gui/elems/plugin/pluginParameter.h \
+src/gui/elems/plugin/pluginParameter.cpp \
src/gui/elems/sampleEditor/waveform.h \
src/gui/elems/sampleEditor/waveform.cpp \
src/gui/elems/sampleEditor/waveTools.h \
src/gui/elems/sampleEditor/pitchTool.cpp \
src/gui/elems/sampleEditor/rangeTool.h \
src/gui/elems/sampleEditor/rangeTool.cpp \
+src/gui/elems/sampleEditor/shiftTool.h \
+src/gui/elems/sampleEditor/shiftTool.cpp \
src/gui/elems/actionEditor/baseActionEditor.h \
src/gui/elems/actionEditor/baseActionEditor.cpp \
src/gui/elems/actionEditor/envelopeEditor.h \
src/gui/elems/mainWindow/mainTransport.cpp \
src/gui/elems/mainWindow/beatMeter.h \
src/gui/elems/mainWindow/beatMeter.cpp \
-src/gui/elems/mainWindow/keyboard/channelMode.h \
-src/gui/elems/mainWindow/keyboard/channelMode.cpp \
-src/gui/elems/mainWindow/keyboard/channelButton.h \
-src/gui/elems/mainWindow/keyboard/channelButton.cpp \
-src/gui/elems/mainWindow/keyboard/channelStatus.h \
-src/gui/elems/mainWindow/keyboard/channelStatus.cpp \
-src/gui/elems/mainWindow/keyboard/keyboard.h \
-src/gui/elems/mainWindow/keyboard/keyboard.cpp \
-src/gui/elems/mainWindow/keyboard/column.h \
-src/gui/elems/mainWindow/keyboard/column.cpp \
-src/gui/elems/mainWindow/keyboard/sampleChannel.h \
-src/gui/elems/mainWindow/keyboard/sampleChannel.cpp \
-src/gui/elems/mainWindow/keyboard/midiChannel.h \
-src/gui/elems/mainWindow/keyboard/midiChannel.cpp \
-src/gui/elems/mainWindow/keyboard/channel.h \
-src/gui/elems/mainWindow/keyboard/channel.cpp \
-src/gui/elems/mainWindow/keyboard/sampleChannelButton.h \
-src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp \
+src/gui/elems/mainWindow/keyboard/channelMode.h \
+src/gui/elems/mainWindow/keyboard/channelMode.cpp \
+src/gui/elems/mainWindow/keyboard/channelButton.h \
+src/gui/elems/mainWindow/keyboard/channelButton.cpp \
+src/gui/elems/mainWindow/keyboard/channelStatus.h \
+src/gui/elems/mainWindow/keyboard/channelStatus.cpp \
+src/gui/elems/mainWindow/keyboard/keyboard.h \
+src/gui/elems/mainWindow/keyboard/keyboard.cpp \
+src/gui/elems/mainWindow/keyboard/column.h \
+src/gui/elems/mainWindow/keyboard/column.cpp \
+src/gui/elems/mainWindow/keyboard/sampleChannel.h \
+src/gui/elems/mainWindow/keyboard/sampleChannel.cpp \
+src/gui/elems/mainWindow/keyboard/midiChannel.h \
+src/gui/elems/mainWindow/keyboard/midiChannel.cpp \
+src/gui/elems/mainWindow/keyboard/channel.h \
+src/gui/elems/mainWindow/keyboard/channel.cpp \
+src/gui/elems/mainWindow/keyboard/sampleChannelButton.h \
+src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp \
+src/gui/elems/mainWindow/keyboard/midiChannelButton.h \
+src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp \
src/gui/elems/config/tabMisc.h \
src/gui/elems/config/tabMisc.cpp \
src/gui/elems/config/tabMidi.h \
src/core/recorder.cpp \
src/utils/fs.cpp \
src/utils/string.cpp \
+src/utils/time.cpp \
src/utils/log.cpp
if WITH_VST
* unlimited number of channels (controllable via computer keyboard);
* several playback modes and combinations;
* BPM and beat sync with sample-accurate loop engine;
-* VST and VSTi (instrument) plugin support;
+* VST and VSTi (instrument) plug-in support;
* MIDI input and output support, featuring custom [MIDI lightning messages](https://github.com/monocasual/giada-midimaps);
* super-sleek, built-in wave editor;
* live sampler from external inputs;
We do our best to make the compilation process as simple as possible. You can find all the information in the [official docs page](http://giadamusic.com/documentation/show/compiling-from-source).
+Something went wrong? Try our new [Docker image](https://github.com/monocasual/giada-docker) for building and running Giada without hurdles.
+
## Bugs, requests and questions for non-developers
Feel free to ask anything on our end-user forum:
Channel::Channel(int type, int status, int bufferSize)
: bufferSize (bufferSize),
midiFilter (-1),
- pan (0.5f),
previewMode (G_PREVIEW_NONE),
+ pan (0.5f),
+ armed (false),
type (type),
status (status),
key (0),
solo (false),
hasActions (false),
readActions (false),
- armed (false),
recStatus (REC_STOPPED),
vChan (nullptr),
guiChannel (nullptr),
/* -------------------------------------------------------------------------- */
-bool Channel::isPlaying()
+bool Channel::isPlaying() const
{
return status & (STATUS_PLAY | STATUS_ENDING);
}
pch.type = type;
pch.index = index;
pch.size = guiChannel->getSize();
+ pch.name = name;
pch.key = key;
+ pch.armed = armed;
pch.column = guiChannel->getColumnIndex();
pch.mute = mute;
pch.mute_s = mute_s;
for (unsigned i=0; i<recorder::global.size(); i++) {
for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
- recorder::action *action = recorder::global.at(i).at(k);
+ recorder::action* action = recorder::global.at(i).at(k);
if (action->chan == index) {
patch::action_t pac;
pac.type = action->type;
unsigned numPlugs = pluginHost::countPlugins(pluginHost::CHANNEL, this);
for (unsigned i=0; i<numPlugs; i++) {
- Plugin *pPlugin = pluginHost::getPluginByIndex(i, pluginHost::CHANNEL, this);
+ Plugin* pPlugin = pluginHost::getPluginByIndex(i, pluginHost::CHANNEL, this);
patch::plugin_t pp;
pp.path = pPlugin->getUniqueId();
pp.bypass = pPlugin->isBypassed();
/* -------------------------------------------------------------------------- */
-int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
+int Channel::readPatch(const string& path, int i, pthread_mutex_t* pluginMutex,
int samplerate, int rsmpQuality)
{
int ret = 1;
- patch::channel_t *pch = &patch::channels.at(i);
+ patch::channel_t* pch = &patch::channels.at(i);
key = pch->key;
+ armed = pch->armed;
type = pch->type;
+ name = pch->name;
index = pch->index;
mute = pch->mute;
mute_s = pch->mute_s;
midiOutLmute = pch->midiOutLmute;
midiOutLsolo = pch->midiOutLsolo;
- for (unsigned k=0; k<pch->actions.size(); k++) {
- patch::action_t *ac = &pch->actions.at(k);
- recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue);
+ for (const patch::action_t& ac : pch->actions) {
+ recorder::rec(index, ac.type, ac.frame, ac.iValue, ac.fValue);
hasActions = true;
}
#ifdef WITH_VST
- for (unsigned k=0; k<pch->plugins.size(); k++) {
- patch::plugin_t *ppl = &pch->plugins.at(k);
- Plugin *plugin = pluginHost::addPlugin(ppl->path, pluginHost::CHANNEL,
+ for (const patch::plugin_t& ppl : pch->plugins) {
+ Plugin* plugin = pluginHost::addPlugin(ppl.path, pluginHost::CHANNEL,
pluginMutex, this);
if (plugin == nullptr) {
ret &= 0;
continue;
}
- plugin->setBypass(ppl->bypass);
- for (unsigned j=0; j<ppl->params.size(); j++)
- plugin->setParameter(j, ppl->params.at(j));
+ plugin->setBypass(ppl.bypass);
+ for (unsigned j=0; j<ppl.params.size(); j++)
+ plugin->setParameter(j, ppl.params.at(j));
plugin->midiInParams.clear();
- for (unsigned j=0; j<ppl->midiInParams.size(); j++)
- plugin->midiInParams.push_back(ppl->midiInParams.at(j));
+ for (uint32_t midiInParam : ppl.midiInParams)
+ plugin->midiInParams.push_back(midiInParam);
ret &= 1;
}
}
-float Channel::getPan()
+float Channel::getPan() const
{
return pan;
}
}
-bool Channel::isPreview()
+bool Channel::isPreview() const
{
return previewMode != G_PREVIEW_NONE;
}
/* -------------------------------------------------------------------------- */
+void Channel::setArmed(bool b)
+{
+ armed = b;
+}
+
+
+bool Channel::isArmed() const
+{
+ return armed;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+std::string Channel::getName() const
+{
+ return name;
+}
+
+
+void Channel::setName(const std::string& s)
+{
+ name = s;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
#ifdef WITH_VST
juce::MidiBuffer &Channel::getPluginMidiEvents()
{
protected:
+ /* sendMidiLMessage
+ Composes a MIDI message by merging bytes from MidiMap conf class, and sends it
+ to KernelMidi. */
+
+ void sendMidiLmessage(uint32_t learn, const giada::m::midimap::message_t& msg);
+
+ /* calcPanning
+ Given an audio channel (stereo: 0 or 1) computes the current panning value. */
+
+ float calcPanning(int ch);
+
#ifdef WITH_VST
- /* MidiBuffer contains MIDI events. When ready, events are sent to
- * each plugin in the channel. This is available for any kind of
- * channel, but it makes sense only for MIDI channels. */
+ /* MidiBuffer contains MIDI events. When ready, events are sent to each plugin
+ in the channel. This is available for any kind of channel, but it makes sense
+ only for MIDI channels. */
juce::MidiBuffer midiBuffer;
#endif
/* bufferSize
- * size of every buffer in this channel (vChan, pChan) */
+ Size of every buffer in this channel (vChan, pChan) */
int bufferSize;
int midiFilter;
- float pan;
-
/* previewMode
Whether the channel is in audio preview mode or not. */
int previewMode;
- /* sendMidiLMessage
- Composes a MIDI message by merging bytes from MidiMap conf class, and sends it
- to KernelMidi. */
-
- void sendMidiLmessage(uint32_t learn, const giada::m::midimap::message_t& msg);
-
- /* calcPanning
- Given an audio channel (stereo: 0 or 1) computes the current panning value. */
-
- float calcPanning(int ch);
+ float pan;
+ bool armed;
+ std::string name;
public:
virtual ~Channel();
/* copy
- * Make a shallow copy (no vChan/pChan allocation) of another channel. */
+ Makes a shallow copy (no vChan/pChan allocation) of another channel. */
virtual void copy(const Channel* src, pthread_mutex_t* pluginMutex) = 0;
/* readPatch
- * Fill channel with data from patch. */
+ Fills channel with data from patch. */
virtual int readPatch(const std::string& basePath, int i,
pthread_mutex_t* pluginMutex, int samplerate, int rsmpQuality);
bool mixerIsRunning, bool forceStart, bool isUserGenerated) = 0;
/* stop
- * action to do when channel is stopped normally (via key or MIDI). */
+ What to do when channel is stopped normally (via key or MIDI). */
virtual void stop() = 0;
/* kill
- * action to do when channel stops abruptly. */
+ What to do when channel stops abruptly. */
virtual void kill(int frame) = 0;
/* mute
- * action to do when channel is muted. If internal == true, set
- * internal mute without altering main mute. */
+ What to do when channel is muted. If internal == true, set internal mute
+ without altering main mute. */
virtual void setMute (bool internal) = 0;
virtual void unsetMute(bool internal) = 0;
/* empty
- * free any associated resources (e.g. waveform for SAMPLE). */
+ Frees any associated resources (e.g. waveform for SAMPLE). */
virtual void empty() = 0;
/* stopBySeq
- * action to do when channel is stopped by sequencer. */
+ What to do when channel is stopped by sequencer. */
virtual void stopBySeq(bool chansStopOnSeqHalt) = 0;
/* quantize
- * start channel according to quantizer. Index = array index of
- * mixer::channels, used by recorder. LocalFrame = frame within the current
- * buffer. */
+ Starts channel according to quantizer. Index = array index of mixer::channels,
+ used by recorder. LocalFrame = frame within the current buffer. */
virtual void quantize(int index, int localFrame) = 0;
/* onZero
- * action to do when frame goes to zero, i.e. sequencer restart. */
+ What to do when frame goes to zero, i.e. sequencer restart. */
virtual void onZero(int frame, bool recsStopOnChanHalt) = 0;
/* onBar
- * action to do when a bar has passed. */
+ What to do when a bar has passed. */
virtual void onBar(int frame) = 0;
/* parseAction
- * do something on a recorded action. Parameters:
- * action *a - action to parse
- * localFrame - frame number of the processed buffer
- * globalFrame - actual frame in Mixer */
+ Does something on a recorded action. Parameters:
+ - action *a - action to parse
+ - localFrame - frame number of the processed buffer
+ - globalFrame - actual frame in Mixer */
// TODO - quantize is useless!
int globalFrame, int quantize, bool mixerIsRunning) = 0;
/* rewind
- * rewind channel when rewind button is pressed. */
+ Rewinds channel when rewind button is pressed. */
virtual void rewind() = 0;
virtual bool canInputRec() = 0;
/* writePatch
- * Fill a patch with channel values. Returns the index of the last
- * Patch::channel_t added. */
+ Fills a patch with channel values. Returns the index of the last
+ Patch::channel_t added. */
virtual int writePatch(int i, bool isProject);
/* receiveMidi
- * Receives and processes midi messages from external devices. */
+ Receives and processes midi messages from external devices. */
virtual void receiveMidi(uint32_t msg);
virtual bool allocBuffers();
- /* ------------------------------------------------------------------------ */
+ /* isPlaying
+ * tell wether the channel is playing or is stopped. */
+
+ bool isPlaying() const;
+
+ /* sendMidiL*
+ * send MIDI lightning events to a physical device. */
+
+ void sendMidiLmute();
+ void sendMidiLsolo();
+ void sendMidiLplay();
+
+ void setPan(float v);
+ float getPan() const;
+
+ void setArmed(bool b);
+ bool isArmed() const;
+
+ std::string getName() const;
+ void setName(const std::string& s);
+
+ void setPreviewMode(int m);
+ bool isPreview() const;
+
+#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. */
+
+ juce::MidiBuffer& getPluginMidiEvents();
+
+ void clearMidiBuffer();
+
+#endif
int index; // unique id
int type; // midi or sample
bool solo;
bool hasActions; // has something recorded
bool readActions; // read what's recorded
- bool armed; // armed for recording
int recStatus; // status of recordings (waiting, ending, ...)
float* vChan; // virtual channel
geChannel* guiChannel; // pointer to a gChannel object, part of the GUI
std::vector <Plugin*> plugins;
#endif
-
- /* ------------------------------------------------------------------------ */
-
- /* isPlaying
- * tell wether the channel is playing or is stopped. */
-
- bool isPlaying();
-
- /* sendMidiL*
- * send MIDI lightning events to a physical device. */
-
- void sendMidiLmute();
- void sendMidiLsolo();
- void sendMidiLplay();
-
- void setPan(float v);
- float getPan();
-
- void setPreviewMode(int m);
- bool isPreview();
-
-#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. */
-
- juce::MidiBuffer& getPluginMidiEvents();
-
- void clearMidiBuffer();
-
-#endif
};
int aboutX = 0;
int aboutY = 0;
+int nameX = 0;
+int nameY = 0;
+
#ifdef WITH_VST
int pluginChooserX = 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;
json_object_set_new(jRoot, CONF_KEY_BEATS_X, json_integer(beatsX));
json_object_set_new(jRoot, CONF_KEY_BEATS_Y, json_integer(beatsY));
json_object_set_new(jRoot, CONF_KEY_ABOUT_X, json_integer(aboutX));
- json_object_set_new(jRoot, CONF_KEY_ABOUT_Y, json_integer(aboutY));
+ json_object_set_new(jRoot, CONF_KEY_ABOUT_Y, json_integer(aboutY));
+ json_object_set_new(jRoot, CONF_KEY_NAME_X, json_integer(nameX));
+ json_object_set_new(jRoot, CONF_KEY_NAME_Y, json_integer(nameY));
json_object_set_new(jRoot, CONF_KEY_MIDI_INPUT_X, json_integer(midiInputX));
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));
extern int bpmX, bpmY;
extern int beatsX, beatsY;
extern int aboutX, aboutY;
+extern int nameX, nameY;
#ifdef WITH_VST
/* -- version --------------------------------------------------------------- */
#define G_APP_NAME "Giada"
-#define G_VERSION_STR "0.14.3"
+#define G_VERSION_STR "0.14.4"
#define G_VERSION_MAJOR 0
#define G_VERSION_MINOR 14
-#define G_VERSION_PATCH 3
+#define G_VERSION_PATCH 4
#define CONF_FILENAME "giada.conf"
#define WID_SAMPLE_EDITOR -8
#define WID_FX -9
#define WID_KEY_GRABBER -10
+#define WID_SAMPLE_NAME -11
#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_MUTE_S "mute_s"
#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 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"
if (kernelAudio::getStatus()) {
kernelAudio::closeDevice();
+ gu_log("[init] KernelAudio closed\n");
mixer::close();
gu_log("[init] Mixer closed\n");
}
#include <rtmidi/RtMidi.h>
#include "../utils/log.h"
#include "../glue/channel.h"
+#include "../glue/plugin.h"
#include "../glue/main.h"
#include "../glue/transport.h"
#include "../glue/io.h"
{
bool status = false;
int api = 0;
-RtMidiOut *midiOut = nullptr;
-RtMidiIn *midiIn = nullptr;
+RtMidiOut* midiOut = nullptr;
+RtMidiIn* midiIn = nullptr;
unsigned numOutPorts = 0;
unsigned numInPorts = 0;
* kernelMidi. 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;
/* -------------------------------------------------------------------------- */
#ifdef WITH_VST
-void processPlugins(Channel *ch, uint32_t pure, uint32_t value)
+void processPlugins(Channel* ch, uint32_t pure, uint32_t value)
{
- /* Plugins' parameters layout reflect the structure of the matrix
- Channel::midiInPlugins. It is safe to assume then that i and k indexes match
- both the structure of Channel::midiInPlugins and vector <Plugin *> *plugins. */
+ /* Plugins' parameters layout reflects the structure of the matrix
+ Channel::midiInPlugins. It is safe to assume then that i (i.e. Plugin*) and k
+ indexes match both the structure of Channel::midiInPlugins and
+ vector<Plugin*>* plugins. */
- vector <Plugin *> *plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
+ vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
- for (unsigned i=0; i<plugins->size(); i++)
- {
- Plugin *plugin = plugins->at(i);
+ for (Plugin* plugin : *plugins) {
for (unsigned k=0; k<plugin->midiInParams.size(); k++) {
uint32_t midiInParam = plugin->midiInParams.at(k);
if (pure != midiInParam)
continue;
- float vf = (value >> 8)/127.0f;
- plugin->setParameter(k, vf);
+ float vf = (value >> 8) / 127.0f;
+ c::plugin::setParameter(plugin, k, vf, false); // false: not from GUI
gu_log(" >>> [plugin %d parameter %d] ch=%d (pure=0x%X, value=%d, float=%f)\n",
- i, k, ch->index, pure, value >> 8, vf);
+ plugin->getId(), k, ch->index, pure, value >> 8, vf);
}
}
}
void processChannels(uint32_t pure, uint32_t value)
{
- for (unsigned i=0; i<mixer::channels.size(); i++) {
-
- Channel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
+ for (Channel* ch : mixer::channels) {
if (!ch->midiIn)
continue;
}
else if (pure == ch->midiInMute) {
gu_log(" >>> mute ch=%d (pure=0x%X)\n", ch->index, pure);
- glue_setMute(ch, false);
+ glue_toggleMute(ch, false);
+ }
+ else if (pure == ch->midiInKill) {
+ gu_log(" >>> kill ch=%d (pure=0x%X)\n", ch->index, pure);
+ glue_kill(ch);
+ }
+ else if (pure == ch->midiInArm) {
+ gu_log(" >>> arm ch=%d (pure=0x%X)\n", ch->index, pure);
+ glue_toggleArm(ch, false);
}
else if (pure == ch->midiInSolo) {
gu_log(" >>> solo ch=%d (pure=0x%X)\n", ch->index, pure);
- ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false);
+ glue_toggleSolo(ch, false);
}
else if (pure == ch->midiInVolume) {
float vf = (value >> 8)/127.0f;
ch->index, pure, value >> 8, vf);
glue_setVolume(ch, vf, false);
}
- else if (pure == ((SampleChannel*)ch)->midiInPitch) {
- float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0]
- gu_log(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
- ch->index, pure, value >> 8, vf);
- glue_setPitch(static_cast<SampleChannel*>(ch), vf);
- }
- else if (pure == ((SampleChannel*)ch)->midiInReadActions) {
- gu_log(" >>> start/stop read actions ch=%d (pure=0x%X)\n", ch->index, pure);
- glue_startStopReadingRecs(static_cast<SampleChannel*>(ch), false);
+ else {
+ SampleChannel* sch = static_cast<SampleChannel*>(ch);
+ if (pure == sch->midiInPitch) {
+ float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0-4.0]
+ gu_log(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
+ sch->index, pure, value >> 8, vf);
+ glue_setPitch(sch, vf);
+ }
+ else
+ if (pure == sch->midiInReadActions) {
+ gu_log(" >>> toggle read actions ch=%d (pure=0x%X)\n", sch->index, pure);
+ glue_toggleReadingRecs(sch, false);
+ }
}
#ifdef WITH_VST
processPlugins(ch, pure, value); // Process plugins' parameters
#endif
- /* Redirect full midi message (pure + value) to plugins */
+ /* Redirect full midi message (pure + value) to plugins. */
+
ch->receiveMidi(pure | value);
}
}
/* -------------------------------------------------------------------------- */
-static void callback(double t, std::vector<unsigned char> *msg, void *data)
+static void callback(double t, std::vector<unsigned char>* msg, void* data)
{
- /* 0.8.0 - for now we handle other midi signals (common and real-time
- * messages) as unknown, for debugging purposes */
+ /* 0.8.0 - for now we handle other MIDI signals (common and real-time
+ messages) as unknown, for debugging purposes. */
if (msg->size() < 3) {
- gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
- for (unsigned i=0; i<msg->size(); i++)
- gu_log("%X", (int) msg->at(i));
- gu_log("\n");
+ //gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
+ //for (unsigned i=0; i<msg->size(); i++)
+ // gu_log("%X", (int) msg->at(i));
+ //gu_log("\n");
return;
}
- /* in this place we want to catch two things: a) note on/note off
- * from a keyboard and b) knob/wheel/slider movements from a
- * controller */
+ /* Here we want to catch two things: a) note on/note off from a keyboard and
+ b) knob/wheel/slider movements from a controller. */
uint32_t input = getIValue(msg->at(0), msg->at(1), msg->at(2));
uint32_t chan = input & 0x0F000000;
uint32_t value = input & 0x0000FF00;
uint32_t pure = 0x00;
if (!conf::noNoteOff)
- pure = input & 0xFFFF0000; // input without 'value' byte
+ pure = input & 0xFFFF0000; // input without 'value' (i.e. velocity) byte
else
- pure = input & 0xFFFFFF00; // input with 'value' byte
+ pure = input & 0xFFFFFF00; // input with 'value' (i.e. velocity) byte
gu_log("[KM] MIDI received - 0x%X (chan %d)\n", input, chan >> 24);
- /* start dispatcher. If midi learn is on don't parse channels, just
- * learn incoming midi signal. Otherwise process master events first,
- * then each channel in the stack. This way incoming signals don't
- * get processed by glue_* when midi learning is on. */
+ /* Start dispatcher. If midi learn is on don't parse channels, just learn
+ incoming MIDI signal. Otherwise process master events first, then each channel
+ in the stack. This way incoming signals don't get processed by glue_* when
+ MIDI learning is on. */
if (cb_learn)
cb_learn(pure, cb_data);
bool midiOut; // enable midi output
uint8_t midiOutChan; // midi output channel
- void copy(const Channel *src, pthread_mutex_t *pluginMutex) override;
+ void copy(const Channel* src, pthread_mutex_t* pluginMutex) override;
void clear() override;
- void process(float *outBuffer, float *inBuffer) override;
- void preview(float *outBuffer) override;
+ void process(float* outBuffer, float *inBuffer) override;
+ void preview(float* outBuffer) override;
void start(int frame, bool doQuantize, int quantize, bool mixerIsRunning,
- bool forceStart, bool isUserGenerated) override;
+ bool forceStart, bool isUserGenerated) override;
void kill(int frame) override;
void empty() override;
void stopBySeq(bool chansStopOnSeqHalt) override;
void rewind() override;
void setMute(bool internal) override;
void unsetMute(bool internal) override;
- int readPatch(const std::string &basePath, int i, pthread_mutex_t *pluginMutex,
+ int readPatch(const std::string& basePath, int i, pthread_mutex_t* pluginMutex,
int samplerate, int rsmpQuality) override;
int writePatch(int i, bool isProject) override;
void quantize(int index, int localFrame) override;
void onZero(int frame, bool recsStopOnChanHalt) override;
void onBar(int frame) override;
- void parseAction(giada::m::recorder::action *a, int localFrame, int globalFrame,
- int quantize, bool mixerIsRunning) override;
+ void parseAction(giada::m::recorder::action* a, int localFrame, int globalFrame,
+ int quantize, bool mixerIsRunning) override;
void receiveMidi(uint32_t msg) override;
bool canInputRec() override;
- /* ------------------------------------------------------------------------ */
-
/* sendMidi
* send Midi event to the outside world. */
- void sendMidi(giada::m::recorder::action *a, int localFrame);
+ void sendMidi(giada::m::recorder::action* a, int localFrame);
void sendMidi(uint32_t data);
#ifdef WITH_VST
if (channels.at(i)->type == CHANNEL_MIDI)
continue;
SampleChannel *ch = static_cast<SampleChannel*>(channels.at(i));
- if (ch->armed)
+ if (ch->isArmed())
memcpy(ch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float));
}
memset(vChanInput, 0, clock::getTotalFrames() * sizeof(float)); // clear vchan
{
#ifdef WITH_VST
-int readPatchPlugins(vector<patch::plugin_t> *list, int type)
+int readPatchPlugins(vector<patch::plugin_t>* list, int type)
{
int ret = 1;
for (unsigned i=0; i<list->size(); i++) {
/* -------------------------------------------------------------------------- */
-bool uniqueSampleName(SampleChannel* ch, const string& name)
+bool uniqueSamplePath(const SampleChannel* skip, const string& path)
{
- for (unsigned i=0; i<mixer::channels.size(); i++) {
- if (ch == mixer::channels.at(i)) // skip itself
- continue;
- if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
+ for (const Channel* ch : mixer::channels) {
+ if (skip == ch || ch->type != CHANNEL_SAMPLE) // skip itself and MIDI channels
continue;
- SampleChannel* other = (SampleChannel*) mixer::channels.at(i);
- if (other->wave != nullptr && name == other->wave->getName())
+ const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
+ if (sch->wave != nullptr && path == sch->wave->getPath())
return false;
}
return true;
continue;
}
- ch->pushWave(wave, false); // false: don't generate name, we provide it
-
- /* Increase lastTakeId until the sample name TAKE-[n] is unique. */
-
- while (!uniqueSampleName(ch, ch->wave->getName())) {
- patch::lastTakeId++;
- ch->wave->setName("TAKE-" + gu_toString(patch::lastTakeId));
- }
+ ch->pushWave(wave);
+ ch->setName("TAKE-" + gu_toString(patch::lastTakeId++)); // Increase lastTakeId
+ channelsReady++;
gu_log("[startInputRec] start input recs using chan %d with size %d "
"frame=%d\n", ch->index, clock::getTotalFrames(), mixer::inputTracker);
-
- channelsReady++;
}
if (channelsReady > 0) {
{
for (unsigned i=0; i<mixer::channels.size(); i++) {
Channel *ch = mixer::channels.at(i);
- if (ch->type == CHANNEL_SAMPLE && ch->armed)
+ if (ch->type == CHANNEL_SAMPLE && ch->isArmed())
return true;
}
return false;
/* addChannel
Adds a new channel of type 'type' into mixer's stack. */
-Channel *addChannel(int type);
+Channel* addChannel(int type);
/* deleteChannel
Completely removes a channel from the stack. */
-int deleteChannel(Channel *ch);
+int deleteChannel(Channel* ch);
/* getChannelByIndex
Returns channel with given index 'i'. */
-Channel *getChannelByIndex(int i);
+Channel* getChannelByIndex(int i);
/* hasLogicalSamples
True if 1 or more samples are logical (memory only, such as takes) */
bool hasEditedSamples();
/* stopSequencer
- * stop the sequencer, with special case if samplesStopOnSeqHalt is
- * true. */
+Stops the sequencer, with special case if samplesStopOnSeqHalt is true. */
void stopSequencer();
/* uniqueSolo
* true if ch is the only solo'd channel in mixer. */
-bool uniqueSolo(Channel *ch);
+bool uniqueSolo(Channel* ch);
/* loadPatch
- * load a path or a project (if isProject) into Mixer. If isProject, path
- * must contain the address of the project folder. */
+Loads a path or a project (if isProject) into Mixer. If isProject, path must
+contain the address of the project folder. */
void readPatch();
/* startInputRec - record from line in
- * creates a new empty wave in the first available channels and returns
- * the chan number chosen, otherwise -1 if there are no more empty
- * channels available. */
+Creates a new empty wave in the first available channels. Returns false if
+something went wrong. */
bool startInputRec();
void stopInputRec();
-/* uniqueSamplename
- * return true if samplename 'n' is unique. Requires SampleChannel *ch
- * in order to skip check against itself. */
+/* uniqueSamplePath
+Returns true if path 'p' is unique. Requires SampleChannel 'skip' in order
+to skip check against itself. */
-bool uniqueSampleName(SampleChannel *ch, const std::string &s);
+bool uniqueSamplePath(const SampleChannel* skip, const std::string& p);
/* hasArmedSampleChannels
Tells whether Mixer has one or more sample channels armed for input
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_TYPE, channel.type)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_INDEX, channel.index)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_SIZE, channel.size)) return 0;
+ if (!storager::setString(jChannel, PATCH_KEY_CHANNEL_NAME, channel.name)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_COLUMN, channel.column)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_MUTE, channel.mute)) return 0;
if (!storager::setInt (jChannel, PATCH_KEY_CHANNEL_MUTE_S, channel.mute_s)) return 0;
if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, channel.midiInPitch)) return 0;
if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, channel.midiOut)) return 0;
if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, channel.midiOutChan)) return 0;
+ if (!storager::setBool (jChannel, PATCH_KEY_CHANNEL_ARMED, channel.armed)) return 0;
readActions(jChannel, &channel);
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE, json_integer(channel.type));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX, json_integer(channel.index));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SIZE, json_integer(channel.size));
+ json_object_set_new(jChannel, PATCH_KEY_CHANNEL_NAME, json_string(channel.name.c_str()));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN, json_integer(channel.column));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE, json_integer(channel.mute));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S, json_integer(channel.mute_s));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, json_integer(channel.midiInPitch));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, json_integer(channel.midiOut));
json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, json_integer(channel.midiOutChan));
+ json_object_set_new(jChannel, PATCH_KEY_CHANNEL_ARMED, json_boolean(channel.armed));
json_array_append_new(jChannels, jChannel);
writeActions(jChannel, &channel.actions);
int type;
int index;
int size;
+ std::string name;
int column;
int mute;
int mute_s;
uint32_t midiOutLplaying;
uint32_t midiOutLmute;
uint32_t midiOutLsolo;
+ bool armed;
// sample channel
std::string samplePath;
int key;
Plugin::Plugin(juce::AudioPluginInstance *plugin, double samplerate,
- int buffersize)
- : ui (nullptr),
- plugin(plugin),
- id (idGenerator++),
- bypass(false)
+ int buffersize)
+ : ui (nullptr),
+ plugin(plugin),
+ id (idGenerator++),
+ bypass(false)
{
- /* Init midiInParams. All values are empty (0x0): they will be filled during
- midi learning process. */
+ /* Init midiInParams. All values are empty (0x0): they will be filled during
+ midi learning process. */
- for (int i=0; i<plugin->getNumParameters(); i++)
- midiInParams.push_back(0x0);
-
- plugin->prepareToPlay(samplerate, buffersize);
+ for (int i=0; i<plugin->getNumParameters(); i++)
+ midiInParams.push_back(0x0);
+
+ plugin->prepareToPlay(samplerate, buffersize);
- gu_log("[Plugin] plugin initialized and ready\n");
+ gu_log("[Plugin] plugin initialized and ready\n");
}
Plugin::~Plugin()
{
closeEditor();
- plugin->suspendProcessing(true);
- plugin->releaseResources();
+ plugin->suspendProcessing(true);
+ plugin->releaseResources();
}
void Plugin::showEditor(void* parent)
{
- ui = plugin->createEditorIfNeeded();
- if (ui == nullptr) {
- gu_log("[Plugin::showEditor] unable to create editor!\n");
- return;
- }
+ ui = plugin->createEditorIfNeeded();
+ if (ui == nullptr) {
+ gu_log("[Plugin::showEditor] unable to create editor!\n");
+ return;
+ }
- /* A silly workaround on X: it seems that calling addToDesktop too fast, i.e.
- before the X Window is fully ready screws up the plugin's event dispatcher. */
+ /* A silly workaround on X: it seems that calling addToDesktop too fast, i.e.
+ before the X Window is fully ready screws up the plugin's event dispatcher. */
#ifdef G_OS_LINUX
- time::sleep(500);
+ time::sleep(500);
#endif
- ui->setOpaque(true);
- ui->addToDesktop(0, parent);
+ ui->setOpaque(true);
+ ui->addToDesktop(0, parent);
}
/* -------------------------------------------------------------------------- */
-bool Plugin::isEditorOpen()
+bool Plugin::isEditorOpen() const
{
- return ui != nullptr && ui->isVisible() && ui->isOnDesktop();
+ return ui != nullptr && ui->isVisible() && ui->isOnDesktop();
}
/* -------------------------------------------------------------------------- */
-string Plugin::getUniqueId()
+string Plugin::getUniqueId() const
{
- return plugin->getPluginDescription().fileOrIdentifier.toStdString();
+ //return plugin->getPluginDescription().fileOrIdentifier.toStdString();
+ return plugin->getPluginDescription().createIdentifierString().toStdString();
}
/* -------------------------------------------------------------------------- */
-int Plugin::getNumParameters()
+int Plugin::getNumParameters() const
{
- return plugin->getNumParameters();
+ return plugin->getNumParameters();
}
/* -------------------------------------------------------------------------- */
-float Plugin::getParameter(int paramIndex)
+float Plugin::getParameter(int paramIndex) const
{
- return plugin->getParameter(paramIndex);
+ return plugin->getParameter(paramIndex);
}
/* -------------------------------------------------------------------------- */
-void Plugin::setParameter(int paramIndex, float value)
+void Plugin::setParameter(int paramIndex, float value) const
{
- return plugin->setParameter(paramIndex, value);
+ return plugin->setParameter(paramIndex, value);
}
/* -------------------------------------------------------------------------- */
-void Plugin::prepareToPlay(double samplerate, int buffersize)
+void Plugin::prepareToPlay(double samplerate, int buffersize) const
{
- plugin->prepareToPlay(samplerate, buffersize);
+ plugin->prepareToPlay(samplerate, buffersize);
}
/* -------------------------------------------------------------------------- */
-string Plugin::getName()
+string Plugin::getName() const
{
- return plugin->getName().toStdString();
+ return plugin->getName().toStdString();
}
/* -------------------------------------------------------------------------- */
-bool Plugin::isSuspended()
+bool Plugin::isSuspended() const
{
- return plugin->isSuspended();
+ return plugin->isSuspended();
}
/* -------------------------------------------------------------------------- */
-void Plugin::process(juce::AudioBuffer<float> &b, juce::MidiBuffer &m)
+bool Plugin::acceptsMidi() const
{
- plugin->processBlock(b, m);
+ return plugin->acceptsMidi();
}
/* -------------------------------------------------------------------------- */
-int Plugin::getNumPrograms()
+bool Plugin::isBypassed() const { return bypass; }
+void Plugin::toggleBypass() { bypass = !bypass; }
+void Plugin::setBypass(bool b) { bypass = b; }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Plugin::getId() const { return id; }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Plugin::getEditorW() const { return ui->getWidth(); }
+int Plugin::getEditorH() const { return ui->getHeight(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Plugin::process(juce::AudioBuffer<float>& b, juce::MidiBuffer m) const
+{
+ plugin->processBlock(b, m);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int Plugin::getNumPrograms() const
{
- return plugin->getNumPrograms();
+ return plugin->getNumPrograms();
}
/* -------------------------------------------------------------------------- */
-int Plugin::getCurrentProgram()
+int Plugin::getCurrentProgram() const
{
- return plugin->getCurrentProgram();
+ return plugin->getCurrentProgram();
}
/* -------------------------------------------------------------------------- */
-void Plugin::setCurrentProgram(int index)
+void Plugin::setCurrentProgram(int index) const
{
- plugin->setCurrentProgram(index);
+ plugin->setCurrentProgram(index);
}
/* -------------------------------------------------------------------------- */
-bool Plugin::hasEditor()
+bool Plugin::hasEditor() const
{
- return plugin->hasEditor();
+ return plugin->hasEditor();
}
/* -------------------------------------------------------------------------- */
-string Plugin::getProgramName(int index)
+string Plugin::getProgramName(int index) const
{
- return plugin->getProgramName(index).toStdString();
+ return plugin->getProgramName(index).toStdString();
}
/* -------------------------------------------------------------------------- */
-string Plugin::getParameterName(int index)
+string Plugin::getParameterName(int index) const
{
- return plugin->getParameterName(index).toStdString();
+ return plugin->getParameterName(index).toStdString();
}
/* -------------------------------------------------------------------------- */
-string Plugin::getParameterText(int index)
+string Plugin::getParameterText(int index) const
{
- return plugin->getParameterText(index).toStdString();
+ return plugin->getParameterText(index).toStdString();
}
/* -------------------------------------------------------------------------- */
-string Plugin::getParameterLabel(int index)
+string Plugin::getParameterLabel(int index) const
{
- return plugin->getParameterLabel(index).toStdString();
+ return plugin->getParameterLabel(index).toStdString();
}
void Plugin::closeEditor()
{
- if (ui == nullptr)
- return;
- delete ui;
- ui = nullptr;
+ if (ui == nullptr)
+ return;
+ delete ui;
+ ui = nullptr;
}
#endif
{
private:
- static int idGenerator;
+ static int idGenerator;
- juce::AudioProcessorEditor *ui; // gui
- juce::AudioPluginInstance *plugin; // core
+ juce::AudioProcessorEditor* ui; // gui
+ juce::AudioPluginInstance* plugin; // core
- int id;
- bool bypass;
+ int id;
+ bool bypass;
public:
- Plugin(juce::AudioPluginInstance *p, double samplerate, int buffersize);
- ~Plugin();
-
- void showEditor(void *parent);
-
- /* closeEditor
- * Shut down plugin GUI. */
-
- void closeEditor();
-
- /* isEditorOpen */
-
- bool isEditorOpen();
-
- /* getUniqueId
- * Return a string-based UID. */
-
- std::string getUniqueId();
-
- std::string getName();
-
- bool hasEditor();
- int getNumParameters();
- float getParameter(int index);
- void setParameter(int index, float value);
- std::string getParameterName(int index);
- std::string getParameterText(int index);
- std::string getParameterLabel(int index);
- void prepareToPlay(double samplerate, int buffersize);
- bool isSuspended();
- void process(juce::AudioBuffer<float> &b, juce::MidiBuffer &m);
- int getNumPrograms();
- int getCurrentProgram();
- void setCurrentProgram(int index);
- std::string getProgramName(int index);
-
- int getId() { return id; }
- bool isBypassed() { return bypass; }
- int getEditorW() { return ui->getWidth(); }
- int getEditorH() { return ui->getHeight(); }
- void toggleBypass() { bypass = !bypass; }
- void setBypass(bool b) { bypass = b; }
-
- /* midiInParams
- A list of midiIn hex values for parameter automation. */
-
- std::vector<uint32_t> midiInParams;
+ Plugin(juce::AudioPluginInstance* p, double samplerate, int buffersize);
+ ~Plugin();
+
+ /* getUniqueId
+ Returns a string-based UID. */
+
+ 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 getNumParameters() const;
+ float getParameter(int index) const;
+ std::string getParameterName(int index) const;
+ std::string getParameterText(int index) const;
+ std::string getParameterLabel(int index) const;
+ bool isSuspended() const;
+ bool isBypassed() const;
+ int getNumPrograms() const;
+ int getCurrentProgram() const;
+ std::string getProgramName(int index) const;
+ int getId() 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;
+
+ void showEditor(void* parent);
+
+ /* closeEditor
+ Shuts down plugin GUI. */
+
+ void closeEditor();
+
+ void toggleBypass();
+ void setBypass(bool b);
+
+ /* midiInParams
+ A list of midiIn hex values for parameter automation. */
+
+ std::vector<uint32_t> midiInParams;
};
#endif
#include "../utils/log.h"
#include "../utils/fs.h"
+#include "../utils/string.h"
#include "const.h"
#include "channel.h"
#include "plugin.h"
{
namespace
{
-juce::MessageManager *messageManager;
+juce::MessageManager* messageManager;
/* pluginFormat
* Plugin format manager. */
/* unknownPluginList
* List of unrecognized plugins found in a patch. */
-std::vector<std::string> unknownPluginList;
+vector<string> unknownPluginList;
-std::vector<Plugin*> masterOut;
-std::vector<Plugin*> masterIn;
+vector<Plugin*> masterOut;
+vector<Plugin*> masterIn;
/* Audio|MidiBuffer
* Dynamic buffers. */
bool missingPlugins;
+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);
+}
+
+
+/* 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, 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;
+ }
+ return nullptr;
+}
}; // {anonymous}
void close()
{
- messageManager->deleteInstance();
+ messageManager->deleteInstance();
}
void init(int _buffersize, int _samplerate)
{
- gu_log("[pluginHost::init] initialize with buffersize=%d, samplerate=%d\n",
- _buffersize, _samplerate);
-
- messageManager = juce::MessageManager::getInstance();
- audioBuffer.setSize(2, _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] initialize with buffersize=%d, samplerate=%d\n",
+ _buffersize, _samplerate);
+
+ messageManager = juce::MessageManager::getInstance();
+ audioBuffer.setSize(2, _buffersize);
+ samplerate = _samplerate;
+ buffersize = _buffersize;
+ missingPlugins = false;
+ //unknownPluginList.empty();
+ loadList(gu_getHomePath() + G_SLASH + "plugins.xml");
+
+ pthread_mutex_init(&mutex_midi, nullptr);
}
/* -------------------------------------------------------------------------- */
-int scanDir(const string &dirpath, void (*callback)(float progress, void *p),
- void *p)
+int scanDir(const string& dirpath, void (*callback)(float progress, void* p),
+ void* p)
{
- gu_log("[pluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str());
- gu_log("[pluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
-
- knownPluginList.clear(); // clear up previous plugins
-
- juce::VSTPluginFormat format;
- juce::FileSearchPath path(dirpath);
- juce::PluginDirectoryScanner scanner(knownPluginList, format, path,
- true, juce::File::nonexistent); // true: recursive
-
- bool cont = true;
- juce::String name;
- while (cont) {
- gu_log("[pluginHost::scanDir] scanning '%s'\n", name.toRawUTF8());
- cont = scanner.scanNextFile(false, name);
- if (callback)
- callback(scanner.getProgress(), p);
- }
-
- gu_log("[pluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
- return knownPluginList.getNumTypes();
+ gu_log("[pluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str());
+ gu_log("[pluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
+
+ knownPluginList.clear(); // clear up previous plugins
+
+ juce::VSTPluginFormat format;
+ juce::FileSearchPath path(dirpath);
+ juce::PluginDirectoryScanner scanner(knownPluginList, format, path,
+ true, juce::File::nonexistent); // true: recursive
+
+ bool cont = true;
+ juce::String name;
+ while (cont) {
+ gu_log("[pluginHost::scanDir] scanning '%s'\n", name.toRawUTF8());
+ cont = scanner.scanNextFile(false, name);
+ if (callback)
+ callback(scanner.getProgress(), p);
+ }
+
+ gu_log("[pluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
+ return knownPluginList.getNumTypes();
}
/* -------------------------------------------------------------------------- */
-int saveList(const string &filepath)
+int saveList(const string& filepath)
{
- 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;
+ 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;
}
/* -------------------------------------------------------------------------- */
-int loadList(const string &filepath)
+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;
+ juce::XmlElement* elem = juce::XmlDocument::parse(juce::File(filepath));
+ if (elem) {
+ knownPluginList.recreateFromXml(*elem);
+ delete elem;
+ return 1;
+ }
+ return 0;
}
/* -------------------------------------------------------------------------- */
-Plugin *addPlugin(const string &fid, int stackType,
- pthread_mutex_t *mutex, Channel *ch)
+Plugin* addPlugin(const string& fid, int stackType, pthread_mutex_t* mutex,
+ Channel* ch)
{
- /* Get the proper stack to add the plugin to */
-
- vector <Plugin *> *pStack;
- pStack = getStack(stackType, ch);
-
- /* Initialize plugin */
-
- juce::PluginDescription *pd = knownPluginList.getTypeForFile(fid);
- if (!pd) {
- gu_log("[pluginHost::addPlugin] no plugin found with fid=%s!\n", fid.c_str());
- missingPlugins = true;
- unknownPluginList.push_back(fid);
- return nullptr;
- }
+ 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());
+ 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());
- Plugin *p = new Plugin(pi, samplerate, buffersize);
+ Plugin* p = new Plugin(pi, samplerate, buffersize);
- /* Try to inject the plugin as soon as possible. */
+ /* 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;
- }
+ 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());
+ 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;
+ return p;
}
/* -------------------------------------------------------------------------- */
-Plugin *addPlugin(int index, int stackType, pthread_mutex_t *mutex,
- Channel *ch)
+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->fileOrIdentifier.toStdString().c_str(), pd->name.toStdString().c_str());
- return addPlugin(pd->fileOrIdentifier.toStdString(), stackType, mutex, ch);
- }
- else {
- gu_log("[pluginHost::addPlugin] no plugins found at index=%d!\n", index);
- return nullptr;
- }
+ 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;
}
/* -------------------------------------------------------------------------- */
-vector <Plugin *> *getStack(int stackType, Channel *ch)
+vector<Plugin*>* getStack(int stackType, Channel* ch)
{
switch(stackType) {
case MASTER_OUT:
/* -------------------------------------------------------------------------- */
-unsigned countPlugins(int stackType, Channel *ch)
+unsigned countPlugins(int stackType, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
return pStack->size();
}
int countAvailablePlugins()
{
- return knownPluginList.getNumTypes();
+ return knownPluginList.getNumTypes();
}
unsigned countUnknownPlugins()
{
- return unknownPluginList.size();
+ 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;
+ 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;
+ return missingPlugins;
};
string getUnknownPluginInfo(int i)
{
- return unknownPluginList.at(i);
+ return unknownPluginList.at(i);
}
/* -------------------------------------------------------------------------- */
-void freeStack(int stackType, pthread_mutex_t *mutex, Channel *ch)
+void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch)
{
- vector <Plugin *> *pStack;
- pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
if (pStack->size() == 0)
return;
while (true) {
if (pthread_mutex_trylock(mutex) != 0)
- continue;
+ continue;
for (unsigned i=0; i<pStack->size(); i++)
- delete pStack->at(i);
+ delete pStack->at(i);
pStack->clear();
pthread_mutex_unlock(mutex);
break;
}
- gu_log("[pluginHost::freeStack] stack type=%d freed\n", stackType);
+ gu_log("[pluginHost::freeStack] stack type=%d freed\n", stackType);
}
/* -------------------------------------------------------------------------- */
-void processStack(float *buffer, int stackType, Channel *ch)
+void processStack(float* buffer, int stackType, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
- /* empty stack, stack not found or mixer not ready: do nothing */
+ /* Empty stack, stack not found or mixer not ready: do nothing. */
if (pStack == nullptr || pStack->size() == 0)
return;
- /* converting buffer from Giada to Juce */
+ /* 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. */
- for (int i=0; i<buffersize; i++) {
- audioBuffer.setSample(0, i, buffer[i*2]);
- audioBuffer.setSample(1, i, buffer[(i*2)+1]);
- }
+ if (ch != nullptr && ch->type == CHANNEL_MIDI)
+ audioBuffer.clear();
+ else
+ for (int i=0; i<buffersize; i++) {
+ audioBuffer.setSample(0, i, buffer[i*2]);
+ audioBuffer.setSample(1, i, buffer[(i*2)+1]);
+ }
/* Hardcore processing. At the end we swap input and output, so that he N-th
- plugin will process the result of the plugin N-1. Part of this loop must be
- guarded by mutexes, i.e. the MIDI process part. You definitely don't want
- a situation like the following one:
- processBlock(...)
- [a new midi event from kernelMidi thread]
- clearMidiBuffer()
- The midi event in between would be surely lost, deleted by clearMidiBuffer! */
-
- for (unsigned i=0; i<pStack->size(); i++) {
- Plugin *plugin = pStack->at(i);
+ 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()
+ The midi event in between would be surely lost, deleted by the last call to
+ channel::clearMidiBuffer()! */
+
+ if (ch != nullptr)
+ pthread_mutex_lock(&mutex_midi);
+
+ for (const Plugin* plugin : *pStack) {
if (plugin->isSuspended() || plugin->isBypassed())
continue;
- if (ch) { // ch might be null if stackType is MASTER_IN/OUT
- pthread_mutex_lock(&mutex_midi);
- plugin->process(audioBuffer, ch->getPluginMidiEvents());
- ch->clearMidiBuffer();
- pthread_mutex_unlock(&mutex_midi);
- }
- else {
- juce::MidiBuffer midiBuffer; // empty buffer
- plugin->process(audioBuffer, midiBuffer);
- }
- }
-
- /* converting buffer from Juce to Giada. A note for the future: if we
- * overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */
+
+ /* 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(2, buffersize);
+ plugin->process(tmp, ch->getPluginMidiEvents());
+ for (int i=0; i<buffersize; i++) {
+ audioBuffer.addSample(0, i, tmp.getSample(0, i));
+ audioBuffer.addSample(1, i, tmp.getSample(1, i));
+ }
+ }
+ else
+ plugin->process(audioBuffer, juce::MidiBuffer()); // Empty MIDI buffer
+ }
+
+ if (ch != nullptr) {
+ ch->clearMidiBuffer();
+ pthread_mutex_unlock(&mutex_midi);
+ }
+
+ /* Converting buffer from Juce to Giada. A note for the future: if we
+ overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */
for (int i=0; i<buffersize; i++) {
buffer[i*2] = audioBuffer.getSample(0, i);
/* -------------------------------------------------------------------------- */
-Plugin *getPluginByIndex(int index, int stackType, Channel *ch)
+Plugin* getPluginByIndex(int index, int stackType, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
if (pStack->size() == 0)
return nullptr;
if ((unsigned) index >= pStack->size())
/* -------------------------------------------------------------------------- */
-int getPluginIndex(int id, int stackType, Channel *ch)
+int getPluginIndex(int id, int stackType, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
for (unsigned i=0; i<pStack->size(); i++)
if (pStack->at(i)->getId() == id)
return i;
void swapPlugin(unsigned indexA, unsigned indexB, int stackType,
- pthread_mutex_t *mutex, Channel *ch)
+ pthread_mutex_t* mutex, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
while (true) {
if (pthread_mutex_trylock(mutex) != 0)
- continue;
+ 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);
/* -------------------------------------------------------------------------- */
-int freePlugin(int id, int stackType, pthread_mutex_t *mutex,
- Channel *ch)
+int freePlugin(int id, int stackType, pthread_mutex_t* mutex, Channel* ch)
{
- vector <Plugin *> *pStack = getStack(stackType, ch);
+ vector<Plugin*>* pStack = getStack(stackType, ch);
for (unsigned i=0; i<pStack->size(); i++) {
- Plugin *pPlugin = pStack->at(i);
+ Plugin *pPlugin = pStack->at(i);
if (pPlugin->getId() != id)
- continue;
+ continue;
while (true) {
if (pthread_mutex_trylock(mutex) != 0)
- continue;
+ 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;
+ return -1;
}
void runDispatchLoop()
{
- messageManager->runDispatchLoopUntil(10);
- //gu_log("[pluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent());
+ messageManager->runDispatchLoopUntil(10);
+ //gu_log("[pluginHost::runDispatchLoop] %d, hasStopMessageBeenSent=%d\n", r, messageManager->hasStopMessageBeenSent());
}
/* -------------------------------------------------------------------------- */
-void freeAllStacks(vector <Channel*> *channels, pthread_mutex_t *mutex)
+void freeAllStacks(vector<Channel*>* channels, pthread_mutex_t* mutex)
{
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();
+ missingPlugins = false;
+ unknownPluginList.clear();
}
/* -------------------------------------------------------------------------- */
-int clonePlugin(Plugin *src, int stackType, pthread_mutex_t *mutex,
- Channel *ch)
+int clonePlugin(Plugin* src, int stackType, pthread_mutex_t* mutex,
+ Channel* ch)
{
- Plugin *p = addPlugin(src->getUniqueId(), stackType, mutex, 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;
/* -------------------------------------------------------------------------- */
-bool doesPluginExist(const string &fid)
+bool doesPluginExist(const string& fid)
{
- return pluginFormat.doesPluginStillExist(*knownPluginList.getTypeForFile(fid));
+ return pluginFormat.doesPluginStillExist(*knownPluginList.getTypeForFile(fid));
}
void sortPlugins(int 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;
- }
+ 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::pluginHost::
* called on each plugin found. Used to update the main window from the GUI
* thread. */
-int scanDir(const std::string &path, void (*callback)(float progress, void *p)=nullptr,
- void *p=nullptr);
+int scanDir(const std::string& path, void (*callback)(float progress, void* p)=nullptr,
+ void* p=nullptr);
/* (save|load)List
* (Save|Load) knownPluginList (in|from) an XML file. */
-int saveList(const std::string &path);
-int loadList(const std::string &path);
+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
* 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);
+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);
/* countPlugins
* Return size of 'stackType'. */
-unsigned countPlugins(int stackType, Channel *ch=nullptr);
+unsigned countPlugins(int stackType, Channel* ch=nullptr);
/* countAvailablePlugins
* Return size of knownPluginList. */
/* freeStack
* free plugin stack of type 'stackType'. */
-void freeStack(int stackType, pthread_mutex_t *mutex, Channel *ch=nullptr);
+void freeStack(int stackType, pthread_mutex_t* mutex, Channel* ch=nullptr);
/* processStack
* apply the fx list to the buffer. */
-void processStack(float *buffer, int stackType, Channel *ch=nullptr);
+void processStack(float* buffer, int stackType, Channel* ch=nullptr);
/* getStack
* Return a std::vector <Plugin *> 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(int stackType, Channel* ch=nullptr);
/* getPluginByIndex */
-Plugin *getPluginByIndex(int index, int stackType, Channel *ch=nullptr);
+Plugin* getPluginByIndex(int index, int stackType, Channel* ch=nullptr);
/* getPluginIndex */
-int getPluginIndex(int id, int stackType, Channel *ch=nullptr);
+int getPluginIndex(int id, int stackType, Channel* ch=nullptr);
/* swapPlugin */
void swapPlugin(unsigned indexA, unsigned indexB, int stackType,
- pthread_mutex_t *mutex, Channel *ch=nullptr);
+ 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);
+ Channel* ch=nullptr);
/* runDispatchLoop
* Wakes up plugins' GUI manager for N milliseconds. */
/* freeAllStacks
* Frees everything. */
-void freeAllStacks(std::vector <Channel*> *channels, pthread_mutex_t *mutex);
+void freeAllStacks(std::vector<Channel*>* channels, pthread_mutex_t* mutex);
/* clonePlugin */
-int clonePlugin(Plugin *src, int stackType, pthread_mutex_t *mutex,
- Channel *ch);
-
+int clonePlugin(Plugin* src, int stackType, pthread_mutex_t* mutex, Channel* ch);
+
/* doesPluginExist */
-bool doesPluginExist(const std::string &fid);
+bool doesPluginExist(const std::string& fid);
bool hasMissingPlugins();
boost (G_DEFAULT_BOOST),
pitch (G_DEFAULT_PITCH),
trackerPreview (0),
+ shift (0),
wave (nullptr),
tracker (0),
mode (G_DEFAULT_CHANMODE),
/* -------------------------------------------------------------------------- */
-void SampleChannel::generateUniqueSampleName()
-{
- string oldName = wave->getName();
- int k = 0;
- while (!mh::uniqueSampleName(this, wave->getName())) {
- wave->setName(oldName + "-" + gu_toString(k));
- k++;
- }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
void SampleChannel::clear()
{
- /** TODO - these memsets can be done only if status PLAY (if below),
+ /** TODO - these memsets may be done only if status PLAY (if below),
* but it would require extra clearPChan calls when samples stop */
std::memset(vChan, 0, sizeof(float) * bufferSize);
/* -------------------------------------------------------------------------- */
-int SampleChannel::save(const char* path)
-{
- return waveManager::save(wave, path);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
void SampleChannel::setBegin(int f)
{
/* TODO - Opaque channel's count - everything in SampleChannel should be
/* -------------------------------------------------------------------------- */
+int SampleChannel::getShift() const { return shift; }
+void SampleChannel::setShift(int s) { shift = s; }
+
+
+/* -------------------------------------------------------------------------- */
+
+
void SampleChannel::setPitch(float v)
{
if (v > G_MAX_PITCH)
/* -------------------------------------------------------------------------- */
-void SampleChannel::pushWave(Wave* w, bool generateName)
+void SampleChannel::pushWave(Wave* w)
{
sendMidiLplay(); // FIXME - why here?!?!
wave = w;
status = STATUS_OFF;
begin = 0;
end = (wave->getSize() - 1) * wave->getChannels(); // TODO - Opaque channels' count
- if (generateName)
- generateUniqueSampleName();
+ name = wave->getBasename();
}
/* -------------------------------------------------------------------------- */
-int SampleChannel::readPatch(const string &basePath, int i,
- pthread_mutex_t *pluginMutex, int samplerate, int rsmpQuality)
+int SampleChannel::readPatch(const string& basePath, int i,
+ pthread_mutex_t* pluginMutex, int samplerate, int rsmpQuality)
{
/* load channel's data first: if the sample is missing or wrong, the channel
* is not completely blank. */
Channel::readPatch("", i, pluginMutex, samplerate, rsmpQuality);
- patch::channel_t *pch = &patch::channels.at(i);
+ const patch::channel_t* pch = &patch::channels.at(i);
mode = pch->mode;
boost = pch->boost;
midiInPitch = pch->midiInPitch;
inputMonitor = pch->inputMonitor;
- Wave *w = nullptr;
+ Wave* w = nullptr;
int res = waveManager::create(basePath + pch->samplePath, &w);
if (res == G_RES_OK) {
pushWave(w);
+ setName(pch->name);
setBegin(pch->begin);
- setEnd (pch->end);
+ setEnd(pch->end);
setPitch(pch->pitch);
}
else {
{
private:
+ /* fillChan
+ Fills 'dest' buffer at point 'offset' with wave data taken from 'start'. If
+ rewind=false don't rewind internal tracker. Returns new sample position,
+ in frames. It resamples data if pitch != 1.0f. */
+
+ int fillChan(float* dest, int start, int offset, bool rewind=true);
+
+ /* clearChan
+ * set data to zero from start to bufferSize-1. */
+
+ void clearChan(float* dest, int start);
+
+ /* calcFadeoutStep
+ * how many frames are left before the end of the sample? Is there
+ * enough room for a complete fadeout? Should we shorten it? */
+
+ void calcFadeoutStep();
+
+ /* calcVolumeEnv
+ * compute any changes in volume done via envelope tool */
+
+ void calcVolumeEnv(int frame);
+
/* rsmp_state, rsmp_data
* structs from libsamplerate */
float boost;
float pitch;
int trackerPreview; // chan position for audio preview
+ int shift;
/* onPreviewEnd
A callback fired when audio preview ends. */
std::function<void()> onPreviewEnd;
- /* fillChan
- Fills 'dest' buffer at point 'offset' with wave data taken from 'start'. If
- rewind=false don't rewind internal tracker. Returns new sample position,
- in frames. It resamples data if pitch != 1.0f. */
-
- int fillChan(float* dest, int start, int offset, bool rewind=true);
-
- /* clearChan
- * set data to zero from start to bufferSize-1. */
-
- void clearChan(float* dest, int start);
-
- /* calcFadeoutStep
- * how many frames are left before the end of the sample? Is there
- * enough room for a complete fadeout? Should we shorten it? */
-
- void calcFadeoutStep();
-
- /* calcVolumeEnv
- * compute any changes in volume done via envelope tool */
-
- void calcVolumeEnv(int frame);
-
- /* generateUniqueSampleName
- * Sample name must be unique. Generate a new samplename with the "-[n]"
- * suffix. */
-
- void generateUniqueSampleName();
-
public:
SampleChannel(int bufferSize, bool inputMonitor);
bool canInputRec() override;
bool allocBuffers() override;
+ int getTrackerPreview() const;
+ int getShift() const;
+ void setShift(int s);
+
void reset(int frame);
/* fade methods
void setXFade(int frame);
/* pushWave
- Adds a new wave to an existing channel. It also generates a unique name
- on request. */
+ Adds a new wave to an existing channel. */
- void pushWave(Wave* w, bool generateName=true);
+ void pushWave(Wave* w);
/* getPosition
* returns the position of an active sample. If EMPTY o MISSING
void setEnd(int f);
int getEnd();
void setTrackerPreview(int f);
- int getTrackerPreview() const;
-
- /* save
- * save sample to file. */
-
- int save(const char* path);
/* hardStop
* stop the channel immediately, no further checks. */
void setOnEndPreviewCb(std::function<void()> f);
- /* ------------------------------------------------------------------------ */
-
Wave* wave;
int tracker; // chan position
int mode; // mode: see const.h
namespace m {
namespace storager
{
-bool setString(json_t *jRoot, const char *key, string &output)
+bool setString(json_t* jRoot, const char* key, string& output)
{
- json_t *jObject = json_object_get(jRoot, key);
- if (!json_is_string(jObject)) {
- gu_log("[storager::setString] key '%s' is not a string!\n", key);
- json_decref(jRoot);
- return false;
- }
- output = json_string_value(jObject);
- return true;
+ json_t* jObject = json_object_get(jRoot, key);
+ if (!jObject) {
+ gu_log("[storager::setString] key '%s' not found, using default value\n", key);
+ output = "";
+ return true;
+ }
+ if (!json_is_string(jObject)) {
+ gu_log("[storager::setString] key '%s' is not a string!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ output = json_string_value(jObject);
+ return true;
}
/* -------------------------------------------------------------------------- */
-bool setFloat(json_t *jRoot, const char *key, float &output)
+bool setFloat(json_t* jRoot, const char* key, float& output)
{
- json_t *jObject = json_object_get(jRoot, key);
- if (!jObject) {
- gu_log("[storager::setFloat] key '%s' not found, using default value\n", key);
- output = 0.0f;
- return true;
- }
- if (!json_is_real(jObject)) {
- gu_log("[storager::setFloat] key '%s' is not a float!\n", key);
- json_decref(jRoot);
- return false;
- }
- output = json_real_value(jObject);
- return true;
+ json_t* jObject = json_object_get(jRoot, key);
+ if (!jObject) {
+ gu_log("[storager::setFloat] key '%s' not found, using default value\n", key);
+ output = 0.0f;
+ return true;
+ }
+ if (!json_is_real(jObject)) {
+ gu_log("[storager::setFloat] key '%s' is not a float!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ output = json_real_value(jObject);
+ return true;
}
/* -------------------------------------------------------------------------- */
-bool setUint32(json_t *jRoot, const char *key, uint32_t &output)
+bool setUint32(json_t* jRoot, const char* key, uint32_t &output)
{
- json_t *jObject = json_object_get(jRoot, key);
- if (!jObject) {
- gu_log("[storager::setUint32] key '%s' not found, using default value\n", key);
- output = 0;
- return true;
- }
- if (!json_is_integer(jObject)) {
- gu_log("[storager::setUint32] key '%s' is not an integer!\n", key);
- json_decref(jRoot);
- return false;
- }
- output = json_integer_value(jObject);
- return true;
+ json_t* jObject = json_object_get(jRoot, key);
+ if (!jObject) {
+ gu_log("[storager::setUint32] key '%s' not found, using default value\n", key);
+ output = 0;
+ return true;
+ }
+ if (!json_is_integer(jObject)) {
+ gu_log("[storager::setUint32] key '%s' is not an integer!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ output = json_integer_value(jObject);
+ return true;
}
/* -------------------------------------------------------------------------- */
-bool setBool(json_t *jRoot, const char *key, bool &output)
+bool setBool(json_t* jRoot, const char* key, bool& output)
{
- json_t *jObject = json_object_get(jRoot, key);
- if (!jObject) {
- gu_log("[storager::setBool] key '%s' not found, using default value\n", key);
- output = false;
- return true;
- }
- if (!json_is_boolean(jObject)) {
- gu_log("[storager::setBool] key '%s' is not a boolean!\n", key);
- json_decref(jRoot);
- return false;
- }
- output = json_boolean_value(jObject);
- return true;
+ json_t* jObject = json_object_get(jRoot, key);
+ if (!jObject) {
+ gu_log("[storager::setBool] key '%s' not found, using default value\n", key);
+ output = false;
+ return true;
+ }
+ if (!json_is_boolean(jObject)) {
+ gu_log("[storager::setBool] key '%s' is not a boolean!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ output = json_boolean_value(jObject);
+ return true;
}
/* -------------------------------------------------------------------------- */
-bool setInt(json_t *jRoot, const char *key, int &output)
+bool setInt(json_t* jRoot, const char* key, int& output)
{
- return setUint32(jRoot, key, (uint32_t&) output);
+ return setUint32(jRoot, key, (uint32_t&) output);
}
/* -------------------------------------------------------------------------- */
-bool checkObject(json_t *jRoot, const char *key)
+bool checkObject(json_t* jRoot, const char* key)
{
- if (!json_is_object(jRoot)) {
- gu_log("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key);
- json_decref(jRoot);
- return false;
- }
- return true;
+ if (!json_is_object(jRoot)) {
+ gu_log("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ return true;
}
/* -------------------------------------------------------------------------- */
-bool checkArray(json_t *jRoot, const char *key)
+bool checkArray(json_t* jRoot, const char* key)
{
- if (!json_is_array(jRoot)) {
- gu_log("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key);
- json_decref(jRoot);
- return false;
- }
- return true;
+ if (!json_is_array(jRoot)) {
+ gu_log("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key);
+ json_decref(jRoot);
+ return false;
+ }
+ return true;
}
}}}; // giada::m::storager::
#include <cstring> // memcpy
#include "../utils/fs.h"
#include "../utils/log.h"
+#include "../utils/string.h"
#include "const.h"
#include "wave.h"
m_bits (bits),
m_logical (false),
m_edited (false),
- m_path (path),
- m_name (gu_stripExt(gu_basename(path)))
+ m_path (path)
{
}
m_bits (other.m_bits),
m_logical (true), // a cloned wave does not exist on disk
m_edited (false),
- m_path (other.m_path),
- m_name (other.m_name)
+ m_path (other.m_path)
{
m_data = new float[m_size];
memcpy(m_data, other.m_data, m_size * sizeof(float));
/* -------------------------------------------------------------------------- */
-void Wave::setName(const string& n)
-{
- string ext = gu_getExt(m_path);
- m_name = gu_stripExt(gu_basename(n));
- m_path = gu_dirname(m_path) + G_SLASH + m_name + "." + ext;
- m_logical = true;
-
- /* A wave with updated m_name must become logical, since the underlying file
- does not exist yet. */
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
int Wave::getRate() const { return m_rate; }
int Wave::getChannels() const { return m_channels; }
std::string Wave::getPath() const { return m_path; }
-std::string Wave::getName() const { return m_name; }
float* Wave::getData() const { return m_data; }
int Wave::getSize() const { return m_size / m_channels; }
int Wave::getBits() const { return m_bits; }
/* -------------------------------------------------------------------------- */
+std::string Wave::getExtension() const
+{
+ return gu_getExt(m_path);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
float* Wave::getFrame(int f) const
{
assert(f >= 0);
void Wave::setRate(int v) { m_rate = v; }
void Wave::setChannels(int v) { m_channels = v; }
-void Wave::setPath(const string& p) { m_path = p; }
void Wave::setLogical(bool l) { m_logical = l; }
void Wave::setEdited(bool e) { m_edited = e; }
/* -------------------------------------------------------------------------- */
+void Wave::setPath(const string& p, int id)
+{
+ if (id == -1)
+ m_path = p;
+ else
+ m_path = gu_stripExt(p) + "-" + gu_toString(id) + "." + gu_getExt(p);
+
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
void Wave::setData(float* d, int size)
{
m_data = d;
bool m_edited; // edited via editor
std::string m_path; // E.g. /path/to/my/sample.wav
- std::string m_name; // Sample name (can be changed)
public:
void setRate(int v);
void setChannels(int v);
- void setPath(const std::string& p);
- void setName(const std::string& p);
void setData(float* data, int size);
void setLogical(bool l);
void setEdited(bool e);
+ /* setPath
+ Sets new path 'p'. If 'id' != -1 inserts a numeric id next to the file
+ extension, e.g. : /path/to/sample-[id].wav */
+
+ void setPath(const std::string& p, int id=-1);
+
std::string getBasename(bool ext=false) const;
+ std::string getExtension() const;
int getRate() const;
int getChannels() const;
std::string getPath() const;
- std::string getName() const;
int getBits() const;
float* getData() const;
int getSize() const; // with channels count
/* -------------------------------------------------------------------------- */
+void shift(Wave* w, int offset)
+{
+ if (offset < 0)
+ offset = (w->getSize() + w->getChannels()) + offset;
+
+ float* begin = w->getData();
+ float* end = w->getData() + (w->getSize() * w->getChannels());
+
+ std::rotate(begin, end - (offset * w->getChannels()), end);
+ w->setEdited(true);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
void reverse(Wave* w, int a, int b)
{
/* https://stackoverflow.com/questions/33201528/reversing-an-array-of-structures-in-c */
- float* begin = (w->getData() + (a * w->getChannels()));
- float* end = (w->getData() + (b * w->getChannels()));
+ float* begin = w->getData() + (a * w->getChannels());
+ float* end = w->getData() + (b * w->getChannels());
std::reverse(begin, end);
void reverse(Wave* w, int a, int b);
+void shift(Wave* w, int offset);
+
}}}; // giada::m::wfx::
#endif
Wave* wave = new Wave(data, size, G_DEFAULT_AUDIO_CHANS, samplerate,
G_DEFAULT_BIT_DEPTH, "");
wave->setLogical(true);
- wave->setName(name);
- wave->setPath(gu_getCurrentPath() + G_SLASH + wave->getName());
*out = wave;
Wave* wave = new Wave(data, size, numChans, src->getRate(),
src->getBits(), src->getPath());
wave->setLogical(true);
- wave->setName(src->getName() + " part");
*out = wave;
-#ifndef __JUCE_APPCONFIG_H__
-#define __JUCE_APPCONFIG_H__
+#ifndef JUCE_APPCONFIG_H
+#define JUCE_APPCONFIG_H
#ifdef _WIN32
Channel* glue_addChannel(int column, int type, int size)
{
- Channel* ch = mh::addChannel(type);
- geChannel* gch = G_MainWin->keyboard->addChannel(column, ch, size);
- ch->guiChannel = gch;
+ Channel* ch = mh::addChannel(type);
+ geChannel* gch = G_MainWin->keyboard->addChannel(column, ch, size);
+ ch->guiChannel = gch;
return ch;
}
/* -------------------------------------------------------------------------- */
-void glue_freeChannel(Channel *ch)
+void glue_freeChannel(Channel* ch)
{
if (ch->status == STATUS_PLAY) {
if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
/* -------------------------------------------------------------------------- */
-void glue_toggleArm(Channel *ch, bool gui)
+void glue_toggleArm(Channel* ch, bool gui)
{
- ch->armed = !ch->armed;
+ ch->setArmed(!ch->isArmed());
if (!gui)
- ch->guiChannel->arm->value(ch->armed);
+ ch->guiChannel->arm->value(ch->isArmed());
}
/* -------------------------------------------------------------------------- */
-void glue_toggleInputMonitor(Channel *ch)
+void glue_toggleInputMonitor(Channel* ch)
{
- SampleChannel *sch = static_cast<SampleChannel*>(ch);
+ SampleChannel* sch = static_cast<SampleChannel*>(ch);
sch->inputMonitor = !sch->inputMonitor;
}
/* -------------------------------------------------------------------------- */
-int glue_cloneChannel(Channel *src)
+int glue_cloneChannel(Channel* src)
{
- Channel *ch = mh::addChannel(src->type);
- geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(),
+ Channel* ch = mh::addChannel(src->type);
+ geChannel* gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(),
ch, src->guiChannel->getSize());
ch->guiChannel = gch;
/* -------------------------------------------------------------------------- */
-void glue_setVolume(Channel *ch, float v, bool gui, bool editor)
+void glue_setVolume(Channel* ch, float v, bool gui, bool editor)
{
ch->volume = v;
/* -------------------------------------------------------------------------- */
-void glue_setMute(Channel *ch, bool gui)
+void glue_toggleMute(Channel* ch, bool gui)
{
if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording)) {
if (!ch->mute) {
/* -------------------------------------------------------------------------- */
-void glue_setSoloOn(Channel *ch, bool gui)
+void glue_toggleSolo(Channel* ch, bool gui)
+{
+ ch->solo ? glue_setSoloOn(ch, gui) : glue_setSoloOff(ch, gui);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_kill(Channel* ch)
+{
+ ch->kill(0); // on frame 0: it's a user-generated event
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_setSoloOn(Channel* ch, bool gui)
{
/* if there's no solo session, store mute configuration of all chans
* and start the session */
/* -------------------------------------------------------------------------- */
-void glue_setSoloOff(Channel *ch, bool gui)
+void glue_setSoloOff(Channel* ch, bool gui)
{
/* if this is uniqueSolo, stop solo session and restore mute status,
* else mute this */
/* -------------------------------------------------------------------------- */
-void glue_setBoost(SampleChannel *ch, float val)
+void glue_setBoost(SampleChannel* ch, float val)
{
ch->setBoost(val);
gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
/* -------------------------------------------------------------------------- */
-void glue_startStopReadingRecs(SampleChannel *ch, bool gui)
+void glue_setName(Channel* ch, const string& name)
+{
+ ch->setName(name);
+ ch->guiChannel->update();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_toggleReadingRecs(SampleChannel* ch, bool gui)
{
/* When you call glue_startReadingRecs with conf::treatRecsAsLoops, the
member value ch->readActions actually is not set to true immediately, because
/* -------------------------------------------------------------------------- */
-void glue_startReadingRecs(SampleChannel *ch, bool gui)
+void glue_startReadingRecs(SampleChannel* ch, bool gui)
{
if (conf::treatRecsAsLoops)
ch->recStatus = REC_WAITING;
/* -------------------------------------------------------------------------- */
-void glue_stopReadingRecs(SampleChannel *ch, bool gui)
+void glue_stopReadingRecs(SampleChannel* ch, bool gui)
{
/* First of all, if the mixer is not running just stop and disable everything.
Then if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put the
/* addChannel
* add an empty new channel to the stack. Returns the new channel. */
-Channel *glue_addChannel(int column, int type, int size);
+Channel* glue_addChannel(int column, int type, int size);
/* loadChannel
* fill an existing channel with a wave. */
-int glue_loadChannel(SampleChannel *ch, const std::string &fname);
+int glue_loadChannel(SampleChannel* ch, const std::string& fname);
/* deleteChannel
* Remove a channel from Mixer. */
-void glue_deleteChannel(Channel *ch);
+void glue_deleteChannel(Channel* ch);
/* freeChannel
* Unload the sample from a sample channel. */
-void glue_freeChannel(Channel *ch);
+void glue_freeChannel(Channel* ch);
/* cloneChannel
* Make an exact copy of Channel *ch. */
-int glue_cloneChannel(Channel *ch);
+int glue_cloneChannel(Channel* ch);
/* toggle/set*
- * Toggle or set several channel properties. If gui == true the signal comes
- * from a manual interaction on the GUI, otherwise it's a MIDI/Jack/external
- * signal. */
-
-void glue_toggleArm(Channel *ch, bool gui=true);
-void glue_toggleInputMonitor(Channel *ch);
-void glue_setMute(Channel *ch, bool gui=true);
-void glue_setSoloOn (Channel *ch, bool gui=true);
-void glue_setSoloOff(Channel *ch, bool gui=true);
-void glue_setVolume(Channel *ch, float v, bool gui=true, bool editor=false);
-
-/* TODO move to glue_sampleEditor */
-void glue_setPitch(SampleChannel *ch, float val);
-
-/* TODO move to glue_sampleEditor */
-void glue_setPanning(SampleChannel *ch, float val);
-
-/* TODO move to glue_sampleEditor */
-void glue_setBoost(SampleChannel *ch, float val);
-
-/* start/stopReadingRecs
+Toggles or set several channel properties. If gui == true the signal comes from
+a manual interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */
+
+void glue_toggleArm(Channel* ch, bool gui=true);
+void glue_toggleInputMonitor(Channel* ch);
+void glue_kill(Channel* ch);
+void glue_toggleMute(Channel* ch, bool gui=true);
+void glue_setSoloOn(Channel* ch, bool gui=true);
+void glue_setSoloOff(Channel* ch, bool gui=true);
+void glue_toggleSolo(Channel* ch, bool gui=true);
+void glue_setVolume(Channel* ch, float v, bool gui=true, bool editor=false);
+void glue_setName(Channel* ch, const std::string& name);
+void glue_setPitch(SampleChannel* ch, float val);
+void glue_setPanning(SampleChannel* ch, float val);
+void glue_setBoost(SampleChannel* ch, float val);
+
+/* toggleReadingRecs
Handles the 'R' button. If gui == true the signal comes from an user interaction
on the GUI, otherwise it's a MIDI/Jack/external signal. */
-void glue_startStopReadingRecs(SampleChannel *ch, bool gui=true);
-void glue_startReadingRecs (SampleChannel *ch, bool gui=true);
-void glue_stopReadingRecs (SampleChannel *ch, bool gui=true);
+void glue_toggleReadingRecs(SampleChannel* ch, bool gui=true);
+void glue_startReadingRecs(SampleChannel* ch, bool gui=true);
+void glue_stopReadingRecs(SampleChannel* ch, bool gui=true);
#endif
void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift)
{
if (ctrl)
- glue_setMute(ch);
+ glue_toggleMute(ch);
else
if (shift)
ch->kill(0); // on frame 0: user-generated event
/* case CTRL */
if (ctrl)
- glue_setMute(ch);
+ glue_toggleMute(ch);
/* case SHIFT
*
if (mixer::channels.at(i)->type == CHANNEL_MIDI)
continue;
SampleChannel *ch = (SampleChannel*) mixer::channels.at(i);
- if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->armed)
+ if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->isArmed())
ch->start(clock::getCurrentFrame(), true, clock::getQuantize(),
clock::isRunning(), true, true);
}
#include "../core/mixer.h"
#include "../core/plugin.h"
#include "../core/channel.h"
+#include "../core/const.h"
+#include "../utils/gui.h"
+#include "../gui/dialogs/gd_mainWindow.h"
+#include "../gui/dialogs/pluginWindow.h"
+#include "../gui/dialogs/pluginList.h"
#include "plugin.h"
+extern gdMainWindow* G_MainWin;
+
+
using namespace giada::m;
-Plugin *glue_addPlugin(Channel *ch, int index, int stackType)
+namespace giada {
+namespace c {
+namespace plugin
+{
+Plugin* addPlugin(Channel* ch, int index, int stackType)
{
if (index >= pluginHost::countAvailablePlugins())
return nullptr;
-
- return pluginHost::addPlugin(index, stackType, &mixer::mutex_plugins, ch);
+ return pluginHost::addPlugin(index, stackType, &mixer::mutex_plugins, ch);
}
/* -------------------------------------------------------------------------- */
-void glue_swapPlugins(Channel *ch, int index1, int index2, int stackType)
+void swapPlugins(Channel* ch, int index1, int index2, int stackType)
{
pluginHost::swapPlugin(index1, index2, stackType, &mixer::mutex_plugins,
ch);
/* -------------------------------------------------------------------------- */
-void glue_freePlugin(Channel *ch, int index, int stackType)
+void freePlugin(Channel* ch, int index, int stackType)
{
pluginHost::freePlugin(index, stackType, &mixer::mutex_plugins, ch);
}
+/* -------------------------------------------------------------------------- */
+
+
+void setParameter(Plugin* p, int index, float value, bool gui)
+{
+ p->setParameter(index, value);
+
+ /* No need to update plug-in editor if it has one: the plug-in's editor takes
+ care of it on its own. Conversely, update the specific parameter for UI-less
+ plug-ins. */
+
+ if (p->hasEditor())
+ return;
+
+ gdPluginList* parent = static_cast<gdPluginList*>(gu_getSubwindow(G_MainWin, WID_FX_LIST));
+ gdPluginWindow* child = static_cast<gdPluginWindow*>(gu_getSubwindow(parent, p->getId() + 1));
+ if (child != nullptr) {
+ Fl::lock();
+ child->updateParameter(index, !gui);
+ Fl::unlock();
+ }
+}
+
+}}}; // giada::c::plugin::
+
+
#endif
#ifdef WITH_VST
-class Plugin *glue_addPlugin(class Channel *ch, int index, int stackType);
-void glue_swapPlugins(class Channel *ch, int indexP1, int indexP2, int stackType);
+class Plugin;
+class Channel;
+
+
+namespace giada {
+namespace c {
+namespace plugin
+{
+Plugin* addPlugin(Channel* ch, int index, int stackType);
+void swapPlugins(Channel* ch, int indexP1, int indexP2, int stackType);
+void freePlugin(Channel* ch, int index, int stackType);
+void setParameter(Plugin* p, int index, float value, bool gui=true);
+}}}; // giada::c::plugin::
-void glue_freePlugin(class Channel *ch, int index, int stackType);
#endif
#include "../gui/elems/sampleEditor/panTool.h"
#include "../gui/elems/sampleEditor/pitchTool.h"
#include "../gui/elems/sampleEditor/rangeTool.h"
+#include "../gui/elems/sampleEditor/shiftTool.h"
#include "../gui/elems/sampleEditor/waveform.h"
#include "../gui/elems/mainWindow/keyboard/channel.h"
#include "../core/sampleChannel.h"
void cut(SampleChannel* ch, int a, int b)
{
+ copy(ch, a, b);
if (!wfx::cut(ch->wave, a, b)) {
gdAlert("Unable to cut the sample!");
return;
void paste(SampleChannel* ch, int a)
{
- if (!isWaveBufferFull())
+ if (!isWaveBufferFull()) {
+ gu_log("[sampleEditor::paste] Buffer is empty, nothing to paste\n");
return;
+ }
wfx::paste(m_waveBuffer, ch->wave, a);
return;
}
- newCh->pushWave(wave, true);
-
+ newCh->pushWave(wave);
newCh->guiChannel->update();
}
return m_waveBuffer != nullptr;
}
+
+/* -------------------------------------------------------------------------- */
+
+
+void shift(SampleChannel* ch, int offset)
+{
+ wfx::shift(ch->wave, offset - ch->getShift());
+ ch->setShift(offset);
+ gdSampleEditor* gdEditor = getSampleEditorWindow();
+ gdEditor->shiftTool->refresh();
+ gdEditor->waveTools->waveform->refresh();
+}
+
+
}}}; // giada::c::sampleEditor::
void silence(SampleChannel* ch, int a, int b);
void fade(SampleChannel* ch, int a, int b, int type);
void smoothEdges(SampleChannel* ch, int a, int b);
+void shift(SampleChannel* ch, int offset);
bool isWaveBufferFull();
#include "../core/patch.h"
#include "../core/sampleChannel.h"
#include "../core/midiChannel.h"
+#include "../core/waveManager.h"
#include "../core/clock.h"
#include "../core/wave.h"
#include "../utils/gui.h"
#include "../utils/log.h"
+#include "../utils/string.h"
#include "../utils/fs.h"
#include "../gui/elems/basics/progress.h"
#include "../gui/elems/mainWindow/keyboard/column.h"
#ifdef WITH_VST
-static void __glue_fillPatchGlobalsPlugins__(vector <Plugin *> *host, vector<patch::plugin_t> *patch)
+static void glue_fillPatchGlobalsPlugins__(vector <Plugin *> *host, vector<patch::plugin_t> *patch)
{
for (unsigned i=0; i<host->size(); i++) {
Plugin *pl = host->at(i);
/* -------------------------------------------------------------------------- */
-static void __glue_fillPatchColumns__()
+static void glue_fillPatchColumns__()
{
for (unsigned i=0; i<G_MainWin->keyboard->getTotalColumns(); i++) {
geColumn *gCol = G_MainWin->keyboard->getColumn(i);
/* -------------------------------------------------------------------------- */
-static void __glue_fillPatchChannels__(bool isProject)
+static void glue_fillPatchChannels__(bool isProject)
{
for (unsigned i=0; i<mixer::channels.size(); i++) {
mixer::channels.at(i)->writePatch(i, isProject);
/* -------------------------------------------------------------------------- */
-static void __glue_fillPatchGlobals__(const string &name)
+static void glue_fillPatchGlobals__(const string &name)
{
patch::version = G_VERSION_STR;
patch::versionMajor = G_VERSION_MAJOR;
#ifdef WITH_VST
- __glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_IN),
+ glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_IN),
&patch::masterInPlugins);
- __glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_OUT),
+ glue_fillPatchGlobalsPlugins__(pluginHost::getStack(pluginHost::MASTER_OUT),
&patch::masterOutPlugins);
#endif
/* -------------------------------------------------------------------------- */
-static bool __glue_savePatch__(const string &fullPath, const string &name,
+static bool glue_savePatch__(const string &fullPath, const string &name,
bool isProject)
{
patch::init();
- __glue_fillPatchGlobals__(name);
- __glue_fillPatchChannels__(isProject);
- __glue_fillPatchColumns__();
+ glue_fillPatchGlobals__(name);
+ glue_fillPatchChannels__(isProject);
+ glue_fillPatchColumns__();
if (patch::write(fullPath)) {
gu_updateMainWinLabel(name);
/* -------------------------------------------------------------------------- */
-void glue_savePatch(void *data)
+static string glue_makeSamplePath__(const string& base, const Wave* w, int k)
{
- gdBrowserSave *browser = (gdBrowserSave*) data;
- string name = browser->getName();
- string fullPath = browser->getCurrentPath() + G_SLASH + gu_stripExt(name) + ".gptc";
+ return base + G_SLASH + w->getBasename(false) + "-" + gu_toString(k) + "." + w->getExtension();
+}
+
+
+static string glue_makeUniqueSamplePath__(const string& base, const SampleChannel* ch)
+{
+ string path = base + G_SLASH + ch->wave->getBasename(true);
+ if (mh::uniqueSamplePath(ch, path))
+ return path;
+
+ int k = 0;
+ path = glue_makeSamplePath__(base, ch->wave, k);
+ while (!mh::uniqueSamplePath(ch, path))
+ path = glue_makeSamplePath__(base, ch->wave, k++);
+ return path;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void glue_savePatch(void* data)
+{
+ gdBrowserSave* browser = (gdBrowserSave*) data;
+ string name = gu_stripExt(browser->getName());
+ string fullPath = browser->getCurrentPath() + G_SLASH + name + ".gptc";
if (name == "") {
gdAlert("Please choose a file name.");
if (!gdConfirmWin("Warning", "File exists: overwrite?"))
return;
- if (__glue_savePatch__(fullPath, name, false)) { // false == not a project
+ if (glue_savePatch__(fullPath, name, false)) { // false == not a project
conf::patchPath = gu_dirname(fullPath);
browser->do_callback();
}
return;
}
- /* close all other windows. This prevents segfault if plugin
- * windows GUIs are on. */
+ /* Close all other windows. This prevents segfault if plugin windows GUIs are
+ open. */
gu_closeAllSubwindows();
- /* reset the system. False(1): don't update the gui right now. False(2): do
- * not create empty columns. */
+ /* Reset the system. False(1): don't update the gui right now. False(2): do
+ not create empty columns. */
glue_resetToInitState(false, false);
browser->setStatusBar(0.1f);
- //__glue_setProgressBar__(status, 0.1f);
- /* Add common stuff, columns and channels. Also increment the progress bar
- * by 0.8 / total_channels steps. */
+ /* Add common stuff, columns and channels. Also increment the progress bar by
+ 0.8 / total_channels steps. */
float steps = 0.8 / patch::channels.size();
for (const patch::column_t& col : patch::columns) {
G_MainWin->keyboard->addColumn(col.width);
- for (unsigned k=0; k<patch::channels.size(); k++) {
- if (patch::channels.at(k).column == col.index) {
- Channel* ch = glue_addChannel(patch::channels.at(k).column,
- patch::channels.at(k).type, patch::channels.at(k).size);
+ unsigned k = 0;
+ for (const patch::channel_t& pch : patch::channels) {
+ if (pch.column == col.index) {
+ Channel* ch = glue_addChannel(pch.column, pch.type, pch.size);
ch->readPatch(basePath, k, &mixer::mutex_plugins, conf::samplerate,
conf::rsmpQuality);
}
browser->setStatusBar(steps);
+ k++;
}
}
- /* fill Mixer */
+ /* Fill Mixer. */
mh::readPatch();
- /* let recorder recompute the actions' positions if the current
- * samplerate != patch samplerate */
+ /* Let recorder recompute the actions' positions if the current
+ samplerate != patch samplerate. */
recorder::updateSamplerate(conf::samplerate, patch::samplerate);
- /* save patchPath by taking the last dir of the broswer, in order to
- * reuse it the next time */
+ /* Save patchPath by taking the last dir of the broswer, in order to reuse it
+ the next time. */
conf::patchPath = gu_dirname(fullPath);
- /* refresh GUI */
+ /* Refresh GUI. */
gu_updateControls();
gu_updateMainWinLabel(patch::name);
browser->setStatusBar(0.1f);
- //__glue_setProgressBar__(status, 1.0f);
gu_log("[glue] patch loaded successfully\n");
/* -------------------------------------------------------------------------- */
-void glue_saveProject(void *data)
+void glue_saveProject(void* data)
{
- gdBrowserSave *browser = (gdBrowserSave*) data;
- string name = browser->getName();
- string folderPath = browser->getCurrentPath(); //browser->getSelectedItem();
- string fullPath = folderPath + G_SLASH + gu_stripExt(name) + ".gprj";
+ gdBrowserSave* browser = (gdBrowserSave*) data;
+ string name = gu_stripExt(browser->getName());
+ string folderPath = browser->getCurrentPath();
+ string fullPath = folderPath + G_SLASH + name + ".gprj";
if (name == "") {
gdAlert("Please choose a project name.");
return;
if (!gu_dirExists(fullPath) && !gu_mkdir(fullPath)) {
- gu_log("[glue_saveProject] unable to make project directory!\n");
+ gu_log("[glue_saveProject] Unable to make project directory!\n");
return;
}
- gu_log("[glue_saveProject] project dir created: %s\n", fullPath.c_str());
+ gu_log("[glue_saveProject] Project dir created: %s\n", fullPath.c_str());
- /* copy all samples inside the folder. Takes and logical ones are saved
- * via glue_saveSample() */
+ /* 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
+ project folder (folderPath). Also make sure the file path is unique inside the
+ project folder.*/
- for (unsigned i=0; i<mixer::channels.size(); i++) {
+ for (const Channel* ch : mixer::channels) {
- if (mixer::channels.at(i)->type == CHANNEL_MIDI)
+ if (ch->type == CHANNEL_MIDI)
continue;
- SampleChannel *ch = (SampleChannel*) mixer::channels.at(i);
+ const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
- if (ch->wave == nullptr)
+ if (sch->wave == nullptr)
continue;
- /* update the new samplePath: everything now comes from the project
- * folder (folderPath). Also remove any existing file. */
+ sch->wave->setPath(glue_makeUniqueSamplePath__(fullPath, sch));
- string samplePath = fullPath + G_SLASH + ch->wave->getBasename(true);
+ gu_log("[glue_saveProject] Save file to %s\n", sch->wave->getPath().c_str());
- if (gu_fileExists(samplePath))
- remove(samplePath.c_str());
- if (ch->save(samplePath.c_str()))
- ch->wave->setPath(samplePath);
+ waveManager::save(sch->wave, sch->wave->getPath()); // TODO - error checking
}
- string gptcPath = fullPath + G_SLASH + gu_stripExt(name) + ".gptc";
- if (__glue_savePatch__(gptcPath, name, true)) // true == it's a project
+ string gptcPath = fullPath + G_SLASH + name + ".gptc";
+ if (glue_savePatch__(gptcPath, name, true)) // true == it's a project
browser->do_callback();
else
gdAlert("Unable to save the project!");
void glue_saveSample(void *data)
{
- gdBrowserSave *browser = (gdBrowserSave*) data;
+ gdBrowserSave* browser = (gdBrowserSave*) data;
string name = browser->getName();
string folderPath = browser->getCurrentPath();
if (!gdConfirmWin("Warning", "File exists: overwrite?"))
return;
- if (static_cast<SampleChannel*>(browser->getChannel())->save(filePath.c_str())) {
+ 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());
conf::samplePath = gu_dirname(filePath);
browser->do_callback();
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <cstring>
+#include "../../utils/gui.h"
+#include "../../utils/string.h"
+#include "../../core/mixer.h"
+#include "../../core/clock.h"
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../glue/main.h"
+#include "../elems/basics/input.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/check.h"
+#include "beatsInput.h"
+#include "gd_mainWindow.h"
+
+
+extern gdMainWindow* mainWin;
+
+
+using namespace giada::m;
+
+
+gdBeatsInput::gdBeatsInput()
+ : gdWindow(180, 60, "Beats")
+{
+ if (conf::beatsX)
+ resize(conf::beatsX, conf::beatsY, w(), h());
+
+ set_modal();
+
+ beats = new geInput(8, 8, 43, G_GUI_UNIT);
+ bars = new geInput(beats->x()+beats->w()+4, 8, 43, G_GUI_UNIT);
+ ok = new geButton(bars->x()+bars->w()+4, 8, 70, G_GUI_UNIT, "Ok");
+ resizeRec = new geCheck(8, 40, 12, 12, "resize recorded actions");
+ end();
+
+ beats->maximum_size(2);
+ beats->value(gu_toString(clock::getBeats()).c_str());
+ beats->type(FL_INT_INPUT);
+
+ bars->maximum_size(2);
+ bars->value(gu_toString(clock::getBars()).c_str());
+ bars->type(FL_INT_INPUT);
+
+ ok->shortcut(FL_Enter);
+ ok->callback(cb_update, (void*)this);
+
+ resizeRec->value(conf::resizeRecordings);
+
+ gu_setFavicon(this);
+ setId(WID_BEATS);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdBeatsInput::~gdBeatsInput()
+{
+ conf::beatsX = x();
+ conf::beatsY = y();
+ conf::resizeRecordings = resizeRec->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBeatsInput::cb_update(Fl_Widget* w, void* p) { ((gdBeatsInput*)p)->cb_update(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBeatsInput::cb_update()
+{
+ if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
+ return;
+ glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value());
+ do_callback();
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_BEATSINPUT_H
+#define GD_BEATSINPUT_H
+
+
+#include "window.h"
+
+
+class geInput;
+class geButton;
+class geCheck;
+
+
+class gdBeatsInput : public gdWindow
+{
+private:
+
+ static void cb_update(Fl_Widget* w, void* p);
+ void cb_update();
+
+ geInput* beats;
+ geInput* bars;
+ geButton* ok;
+ geCheck* resizeRec;
+
+public:
+
+ gdBeatsInput();
+ ~gdBeatsInput();
+};
+
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <cstring>
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../core/mixer.h"
+#include "../../core/clock.h"
+#include "../../glue/main.h"
+#include "../../utils/gui.h"
+#include "../../utils/string.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/input.h"
+#include "bpmInput.h"
+#include "gd_mainWindow.h"
+
+
+extern gdMainWindow *mainWin;
+
+
+using std::vector;
+using std::string;
+using namespace giada::m;
+
+
+gdBpmInput::gdBpmInput(const char* label)
+: gdWindow(144, 36, "Bpm")
+{
+ if (conf::bpmX)
+ resize(conf::bpmX, 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");
+ end();
+
+ input_a->maximum_size(3);
+ input_a->type(FL_INT_INPUT);
+ input_a->value(gu_toString(clock::getBpm()).c_str());
+
+ /* Use the decimal value from the string label. */
+
+ vector<string> tokens;
+ gu_split(label, ".", &tokens);
+ 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);
+ setId(WID_BPM);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdBpmInput::~gdBpmInput()
+{
+ conf::bpmX = x();
+ conf::bpmY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBpmInput::cb_update(Fl_Widget* w, void* p) { ((gdBpmInput*)p)->cb_update(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBpmInput::cb_update()
+{
+ if (strcmp(input_a->value(), "") == 0)
+ return;
+ glue_setBpm(input_a->value(), input_b->value());
+ do_callback();
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_BPMINPUT_H
+#define GD_BPMINPUT_H
+
+
+#include "window.h"
+
+
+class geInput;
+class geButton;
+
+
+class gdBpmInput : public gdWindow
+{
+private:
+
+ static void cb_update(Fl_Widget* w, void* p);
+ void cb_update();
+
+ geInput* input_a;
+ geInput* input_b;
+ geButton* ok;
+
+public:
+
+ gdBpmInput(const char* label); // pointer to mainWin->timing->bpm->label()
+ ~gdBpmInput();
+};
+
+#endif
using namespace giada::m;
-gdBrowserBase::gdBrowserBase(int x, int y, int w, int h, const string &title,
- const string &path, void (*callback)(void*))
+gdBrowserBase::gdBrowserBase(int x, int y, int w, int h, const string& title,
+ const string& path, void (*callback)(void*))
: gdWindow(x, y, w, h, title.c_str()), callback(callback)
{
set_non_modal();
groupTop = new Fl_Group(8, 8, w-16, 40);
hiddenFiles = new geCheck(groupTop->x(), groupTop->y(), 400, 20, "Show hidden files");
- where = new geInput(groupTop->x(), hiddenFiles->y()+hiddenFiles->h(), 152, 20);
+ where = new geInput(groupTop->x(), hiddenFiles->y()+hiddenFiles->h(), 20, 20);
updir = new geButton(groupTop->x()+groupTop->w()-20, where->y(), 20, 20, "", updirOff_xpm, updirOn_xpm);
groupTop->end();
groupTop->resizable(where);
/* -------------------------------------------------------------------------- */
-void gdBrowserBase::cb_up (Fl_Widget *v, void *p) { ((gdBrowserBase*)p)->__cb_up(); }
-void gdBrowserBase::cb_close(Fl_Widget *v, void *p) { ((gdBrowserBase*)p)->__cb_close(); }
-void gdBrowserBase::cb_toggleHiddenFiles(Fl_Widget *v, void *p) { ((gdBrowserBase*)p)->__cb_toggleHiddenFiles(); }
+void gdBrowserBase::cb_up (Fl_Widget* v, void* p) { ((gdBrowserBase*)p)->cb_up(); }
+void gdBrowserBase::cb_close(Fl_Widget* v, void* p) { ((gdBrowserBase*)p)->cb_close(); }
+void gdBrowserBase::cb_toggleHiddenFiles(Fl_Widget *v, void *p) { ((gdBrowserBase*)p)->cb_toggleHiddenFiles(); }
/* -------------------------------------------------------------------------- */
-void gdBrowserBase::__cb_up()
+void gdBrowserBase::cb_up()
{
string dir = browser->getCurrentDir();
- dir = dir.substr(0, dir.find_last_of(G_SLASH_STR)); // remove up to the next slash
+
+ /* Take 'dir' path and remove all chars up to the next slash, e.g.:
+ /path/to/my/dir -> /path/to/my
+ Make sure not to remove the leading '/' (OS X/Linux only). */
+
+ dir = dir.substr(0, dir.find_last_of(G_SLASH_STR));
+
+#if defined(G_OS_MAC) || defined(G_OS_LINUX)
+
+ if (dir.empty())
+ dir = G_SLASH_STR;
+
+#endif
+
browser->loadDir(dir);
where->value(browser->getCurrentDir().c_str());
}
/* -------------------------------------------------------------------------- */
-void gdBrowserBase::__cb_close()
+void gdBrowserBase::cb_close()
{
do_callback();
}
/* -------------------------------------------------------------------------- */
-void gdBrowserBase::__cb_toggleHiddenFiles()
+void gdBrowserBase::cb_toggleHiddenFiles()
{
browser->toggleHiddenFiles();
}
{
protected:
- Channel *channel;
-
- Fl_Group *groupTop;
- geCheck *hiddenFiles;
- geBrowser *browser;
- geButton *ok;
- geButton *cancel;
- geInput *where;
- geButton *updir;
- geProgress *status;
-
- static void cb_up (Fl_Widget *v, void *p);
- static void cb_close (Fl_Widget *w, void *p);
- static void cb_toggleHiddenFiles(Fl_Widget *w, void *p);
-
- inline void __cb_up ();
- inline void __cb_close ();
- inline void __cb_toggleHiddenFiles();
+ Channel* channel;
+
+ Fl_Group* groupTop;
+ geCheck* hiddenFiles;
+ geBrowser* browser;
+ geButton* ok;
+ geButton* cancel;
+ geInput* where;
+ geButton* updir;
+ geProgress* status;
+
+ static void cb_up(Fl_Widget* v, void* p);
+ static void cb_close(Fl_Widget* w, void* p);
+ static void cb_toggleHiddenFiles(Fl_Widget* w, void* p);
+ void cb_up();
+ void cb_close();
+ void cb_toggleHiddenFiles();
/* Callback
* Fired when the save/load button is pressed. */
void (*callback)(void*);
- gdBrowserBase(int x, int y, int w, int h, const std::string &title,
- const std::string &path, void (*callback)(void*));
+ gdBrowserBase(int x, int y, int w, int h, const std::string& title,
+ const std::string& path, void (*callback)(void*));
public:
void showStatusBar();
void hideStatusBar();
- std::string getCurrentPath();
+ std::string getCurrentPath();
- Channel *getChannel() { return channel; }
+ Channel* getChannel() { return channel; }
void fireCallback() { callback((void*) this); }
};
using std::string;
-gdBrowserLoad::gdBrowserLoad(int x, int y, int w, int h, const string &title,
- const string &path, void (*cb)(void*), Channel *ch)
+gdBrowserLoad::gdBrowserLoad(int x, int y, int w, int h, const string& title,
+ const string& path, void (*cb)(void*), Channel* ch)
: gdBrowserBase(x, y, w, h, title, path, cb)
{
channel = ch;
ok->label("Load");
ok->callback(cb_load, (void*) this);
ok->shortcut(FL_ENTER);
+
+ /* On OS X the 'where' input doesn't get resized properly on startup. Let's
+ force it. */
+
+ where->redraw();
}
/* -------------------------------------------------------------------------- */
-void gdBrowserLoad::cb_load(Fl_Widget *v, void *p) { ((gdBrowserLoad*)p)->__cb_load(); }
-void gdBrowserLoad::cb_down(Fl_Widget *v, void *p) { ((gdBrowserLoad*)p)->__cb_down(); }
+void gdBrowserLoad::cb_load(Fl_Widget* v, void* p) { ((gdBrowserLoad*)p)->cb_load(); }
+void gdBrowserLoad::cb_down(Fl_Widget* v, void* p) { ((gdBrowserLoad*)p)->cb_down(); }
/* -------------------------------------------------------------------------- */
-void gdBrowserLoad::__cb_load()
+void gdBrowserLoad::cb_load()
{
callback((void*) this);
}
/* -------------------------------------------------------------------------- */
-void gdBrowserLoad::__cb_down()
+void gdBrowserLoad::cb_down()
{
string path = browser->getSelectedItem();
{
private:
- static void cb_load(Fl_Widget *w, void *p);
- static void cb_down(Fl_Widget *v, void *p);
-
- inline void __cb_load();
- inline void __cb_down();
+ static void cb_load(Fl_Widget* w, void* p);
+ static void cb_down(Fl_Widget* v, void* p);
+ void cb_load();
+ void cb_down();
public:
- gdBrowserLoad(int x, int y, int w, int h, const std::string &title,
- const std::string &path, void (*callback)(void*), Channel *ch);
+ gdBrowserLoad(int x, int y, int w, int h, const std::string& title,
+ const std::string& path, void (*callback)(void*), Channel* ch);
};
using std::string;
-gdBrowserSave::gdBrowserSave(int x, int y, int w, int h, const string &title,
- const string &path, const string &_name, void (*cb)(void*), Channel *ch)
+gdBrowserSave::gdBrowserSave(int x, int y, int w, int h, const string& title,
+ const string& path, const string& _name, void (*cb)(void*), Channel* ch)
: gdBrowserBase(x, y, w, h, title, path, cb)
{
channel = ch;
ok->label("Save");
ok->callback(cb_save, (void*) this);
ok->shortcut(FL_ENTER);
+
+ /* On OS X the 'where' and 'name' inputs don't get resized properly on startup.
+ Let's force them. */
+
+ where->redraw();
+ name->redraw();
}
/* -------------------------------------------------------------------------- */
-void gdBrowserSave::cb_save(Fl_Widget *v, void *p) { ((gdBrowserSave*)p)->__cb_save(); }
-void gdBrowserSave::cb_down(Fl_Widget *v, void *p) { ((gdBrowserSave*)p)->__cb_down(); }
+void gdBrowserSave::cb_save(Fl_Widget* v, void* p) { ((gdBrowserSave*)p)->cb_save(); }
+void gdBrowserSave::cb_down(Fl_Widget* v, void* p) { ((gdBrowserSave*)p)->cb_down(); }
/* -------------------------------------------------------------------------- */
-void gdBrowserSave::__cb_down()
+void gdBrowserSave::cb_down()
{
string path = browser->getSelectedItem();
/* -------------------------------------------------------------------------- */
-void gdBrowserSave::__cb_save()
+void gdBrowserSave::cb_save()
{
callback((void*) this);
}
{
private:
- geInput *name;
+ geInput* name;
- static void cb_down(Fl_Widget *v, void *p);
- static void cb_save(Fl_Widget *w, void *p);
-
- inline void __cb_down();
- inline void __cb_save();
+ static void cb_down(Fl_Widget* v, void* p);
+ static void cb_save(Fl_Widget* w, void* p);
+ void cb_down();
+ void cb_save();
public:
- gdBrowserSave(int x, int y, int w, int h, const std::string &title,
- const std::string &path, const std::string &name, void (*callback)(void*),
- Channel *ch);
+ gdBrowserSave(int x, int y, int w, int h, const std::string& title,
+ const std::string& path, const std::string& name, void (*callback)(void*),
+ Channel* ch);
std::string getName();
};
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "../../glue/channel.h"
+#include "../../utils/gui.h"
+#include "../../core/const.h"
+#include "../../core/conf.h"
+#include "../../core/channel.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/input.h"
+#include "channelNameInput.h"
+
+
+using namespace giada::m;
+
+
+gdChannelNameInput::gdChannelNameInput(Channel* ch)
+: gdWindow(400, 64, "New channel name"),
+ m_ch (ch)
+{
+ if (conf::nameX)
+ resize(conf::nameX, conf::nameY, w(), h());
+
+ set_modal();
+
+ m_name = new geInput(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w() - (G_GUI_OUTER_MARGIN * 2), G_GUI_UNIT);
+ m_ok = new geButton(w() - 70 - G_GUI_OUTER_MARGIN, m_name->y()+m_name->h() + G_GUI_OUTER_MARGIN, 70, G_GUI_UNIT, "Ok");
+ m_cancel = new geButton(m_ok->x() - 70 - G_GUI_OUTER_MARGIN, m_ok->y(), 70, G_GUI_UNIT, "Cancel");
+ end();
+
+ m_name->value(m_ch->getName().c_str());
+
+ m_ok->shortcut(FL_Enter);
+ m_ok->callback(cb_update, (void*)this);
+
+ m_cancel->callback(cb_cancel, (void*)this);
+
+ gu_setFavicon(this);
+ setId(WID_SAMPLE_NAME);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdChannelNameInput::~gdChannelNameInput()
+{
+ conf::nameX = x();
+ conf::nameY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdChannelNameInput::cb_update(Fl_Widget* w, void* p) { ((gdChannelNameInput*)p)->cb_update(); }
+void gdChannelNameInput::cb_cancel(Fl_Widget* w, void* p) { ((gdChannelNameInput*)p)->cb_cancel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdChannelNameInput::cb_cancel()
+{
+ do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdChannelNameInput::cb_update()
+{
+ glue_setName(m_ch, m_name->value());
+ do_callback();
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_CHANNEL_NAME_INPUT_H
+#define GD_CHANNEL_NAME_INPUT_H
+
+
+#include "window.h"
+
+
+class Channel;
+class geInput;
+class geButton;
+
+
+class gdChannelNameInput : public gdWindow
+{
+private:
+
+ static void cb_update(Fl_Widget* w, void* p);
+ static void cb_cancel(Fl_Widget* w, void* p);
+ void cb_update();
+ void cb_cancel();
+
+ Channel* m_ch;
+
+ geInput* m_name;
+ geButton* m_ok;
+ geButton* m_cancel;
+
+public:
+
+ gdChannelNameInput(Channel* ch);
+ ~gdChannelNameInput();
+};
+
+#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 "../../core/mixer.h"
-#include "../../core/clock.h"
-#include "../../core/conf.h"
-#include "../../core/const.h"
-#include "../../glue/main.h"
-#include "../elems/basics/input.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/check.h"
-#include "gd_beatsInput.h"
-#include "gd_mainWindow.h"
-
-
-extern gdMainWindow *mainWin;
-
-
-using namespace giada::m;
-
-
-gdBeatsInput::gdBeatsInput()
- : gdWindow(164, 60, "Beats")
-{
- if (conf::beatsX)
- resize(conf::beatsX, conf::beatsY, w(), h());
-
- set_modal();
-
- beats = new geInput(8, 8, 35, 20);
- bars = new geInput(47, 8, 35, 20);
- ok = new geButton(86, 8, 70, 20, "Ok");
- resizeRec = new geCheck(8, 40, 12, 12, "resize recorded actions");
- end();
-
- char buf_bars[3]; sprintf(buf_bars, "%d", clock::getBars());
- char buf_beats[3]; sprintf(buf_beats, "%d", clock::getBeats());
- beats->maximum_size(2);
- beats->value(buf_beats);
- beats->type(FL_INT_INPUT);
- bars->maximum_size(2);
- bars->value(buf_bars);
- bars->type(FL_INT_INPUT);
- ok->shortcut(FL_Enter);
- ok->callback(cb_update_batt, (void*)this);
- resizeRec->value(conf::resizeRecordings);
-
- gu_setFavicon(this);
- setId(WID_BEATS);
- show();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-gdBeatsInput::~gdBeatsInput()
-{
- conf::beatsX = x();
- conf::beatsY = y();
- conf::resizeRecordings = resizeRec->value();
-}
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBeatsInput::cb_update_batt(Fl_Widget *w, void *p) { ((gdBeatsInput*)p)->__cb_update_batt(); }
-
-
-/* ------------------------------------------------------------------ */
-
-
-void gdBeatsInput::__cb_update_batt()
-{
- if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
- return;
- glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value());
- do_callback();
-}
+++ /dev/null
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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_BEATSINPUT_H
-#define GD_BEATSINPUT_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "window.h"
-
-
-class geInput;
-class geButton;
-class geCheck;
-
-
-class gdBeatsInput : public gdWindow
-{
-private:
-
- static void cb_update_batt(Fl_Widget *w, void *p);
- inline void __cb_update_batt();
-
- geInput *beats;
- geInput *bars;
- geButton *ok;
- geCheck *resizeRec;
-
-public:
-
- gdBeatsInput();
- ~gdBeatsInput();
-};
-
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 <cstring>
-#include "../../core/conf.h"
-#include "../../core/const.h"
-#include "../../core/mixer.h"
-#include "../../core/clock.h"
-#include "../../glue/main.h"
-#include "../../utils/gui.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/input.h"
-#include "gd_bpmInput.h"
-#include "gd_mainWindow.h"
-
-
-extern gdMainWindow *mainWin;
-
-
-using namespace giada::m;
-
-
-gdBpmInput::gdBpmInput(const char *label)
-: gdWindow(144, 36, "Bpm")
-{
- if (conf::bpmX)
- resize(conf::bpmX, conf::bpmY, w(), h());
-
- set_modal();
-
- input_a = new geInput(8, 8, 30, 20);
- input_b = new geInput(42, 8, 20, 20);
- ok = new geButton(66, 8, 70, 20, "Ok");
- end();
-
- char a[4];
- snprintf(a, 4, "%d", (int) clock::getBpm());
- char b[2];
- for (unsigned i=0; i<strlen(label); i++) // looking for the dot
- if (label[i] == '.') {
- snprintf(b, 2, "%c", label[i+1]);
- break;
- }
-
- input_a->maximum_size(3);
- input_a->type(FL_INT_INPUT);
- input_a->value(a);
- input_b->maximum_size(1);
- input_b->type(FL_INT_INPUT);
- input_b->value(b);
-
- ok->shortcut(FL_Enter);
- ok->callback(cb_update_bpm, (void*)this);
-
- gu_setFavicon(this);
- setId(WID_BPM);
- show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdBpmInput::~gdBpmInput()
-{
- conf::bpmX = x();
- conf::bpmY = y();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBpmInput::cb_update_bpm(Fl_Widget *w, void *p) { ((gdBpmInput*)p)->__cb_update_bpm(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdBpmInput::__cb_update_bpm()
-{
- if (strcmp(input_a->value(), "") == 0)
- return;
- glue_setBpm(input_a->value(), input_b->value());
- do_callback();
-}
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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_BPMINPUT_H
-#define GD_BPMINPUT_H
-
-
-#include "window.h"
-
-
-class geInput;
-class geButton;
-
-
-class gdBpmInput : public gdWindow
-{
-private:
-
- static void cb_update_bpm(Fl_Widget *w, void *p);
- inline void __cb_update_bpm();
-
- geInput *input_a;
- geInput *input_b;
- geButton *ok;
-
-public:
-
- gdBpmInput(const char *label); // pointer to mainWin->timing->bpm->label()
- ~gdBpmInput();
-};
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 "../../glue/plugin.h"
-#include "../../utils/gui.h"
-#include "../../core/channel.h"
-#include "../../core/conf.h"
-#include "../../core/pluginHost.h"
-#include "../elems/pluginBrowser.h"
-#include "../elems/basics/button.h"
-#include "../elems/basics/choice.h"
-#include "../elems/basics/box.h"
-#include "gd_pluginChooser.h"
-
-
-using namespace giada::m;
-
-
-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)
-{
- /* top area */
- Fl_Group *group_top = new Fl_Group(8, 8, w()-16, 20);
- sortMethod = new geChoice(group_top->x() + 45, group_top->y(), 100, 20, "Sort by");
- geBox *b1 = new geBox(sortMethod->x()+sortMethod->w(), group_top->y(), 100, 20); // spacer window border <-> menu
- group_top->resizable(b1);
- group_top->end();
-
- /* center browser */
- browser = new gePluginBrowser(8, 36, w()-16, h()-70);
-
- /* ok/cancel buttons */
- Fl_Group *group_btn = new Fl_Group(8, browser->y()+browser->h()+8, w()-16, h()-browser->h()-16);
- geBox *b2 = new geBox(8, browser->y()+browser->h(), 100, 20); // spacer window border <-> buttons
- addBtn = new geButton(w()-88, group_btn->y(), 80, 20, "Add");
- cancelBtn = new geButton(addBtn->x()-88, group_btn->y(), 80, 20, "Cancel");
- group_btn->resizable(b2);
- group_btn->end();
-
- end();
-
- sortMethod->add("Name");
- sortMethod->add("Category");
- sortMethod->add("Manufacturer");
- sortMethod->callback(cb_sort, (void*) this);
- sortMethod->value(conf::pluginSortMethod);
-
- addBtn->callback(cb_add, (void*) this);
- addBtn->shortcut(FL_Enter);
- cancelBtn->callback(cb_close, (void*) this);
-
- resizable(browser);
- gu_setFavicon(this);
- show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdPluginChooser::~gdPluginChooser()
-{
- conf::pluginChooserX = x();
- conf::pluginChooserY = y();
- conf::pluginChooserW = w();
- conf::pluginChooserH = h();
- conf::pluginSortMethod = sortMethod->value();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginChooser::cb_close(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_close(); }
-void gdPluginChooser::cb_add(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_add(); }
-void gdPluginChooser::cb_sort(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_sort(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginChooser::__cb_close()
-{
- do_callback();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginChooser::__cb_sort()
-{
- pluginHost::sortPlugins(sortMethod->value());
- browser->refresh();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginChooser::__cb_add()
-{
- int index = browser->value() - 3; // subtract header lines
- if (index < 0)
- return;
- glue_addPlugin(ch, index, stackType);
- do_callback();
-}
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 GD_PLUGIN_CHOOSER_H
-#define GD_PLUGIN_CHOOSER_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include "window.h"
-
-
-class Channel;
-class geChoice;
-class geButton;
-class geButton;
-class gePluginBrowser;
-
-
-class gdPluginChooser : public gdWindow
-{
-private:
-
- Channel *ch; // ch == nullptr ? masterOut
- int stackType;
-
- geChoice *sortMethod;
- geButton *addBtn;
- geButton *cancelBtn;
- gePluginBrowser *browser;
-
- static void cb_close(Fl_Widget *w, void *p);
- static void cb_add (Fl_Widget *w, void *p);
- static void cb_sort (Fl_Widget *w, void *p);
- inline void __cb_close();
- inline void __cb_add ();
- inline void __cb_sort ();
-
-public:
-
- gdPluginChooser(int x, int y, int w, int h, int stackType, Channel *ch=nullptr);
- ~gdPluginChooser();
-};
-
-
-#endif
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 "../../utils/gui.h"
-#include "../../utils/fs.h"
-#include "../../core/conf.h"
-#include "../../core/const.h"
-#include "../../core/graphics.h"
-#include "../../core/pluginHost.h"
-#include "../../core/plugin.h"
-#include "../../core/mixer.h"
-#include "../../core/channel.h"
-#include "../../glue/plugin.h"
-#include "../../utils/log.h"
-#include "../../utils/string.h"
-#include "../elems/basics/boxtypes.h"
-#include "../elems/basics/idButton.h"
-#include "../elems/basics/statusButton.h"
-#include "../elems/basics/choice.h"
-#include "../elems/mainWindow/mainIO.h"
-#include "../elems/mainWindow/keyboard/channel.h"
-#include "gd_pluginList.h"
-#include "gd_pluginChooser.h"
-#include "gd_pluginWindow.h"
-#include "gd_pluginWindowGUI.h"
-#include "gd_mainWindow.h"
-
-
-extern gdMainWindow *G_MainWin;
-
-
-using std::string;
-using namespace giada::m;
-
-
-gdPluginList::gdPluginList(int stackType, Channel *ch)
- : gdWindow(468, 204), ch(ch), stackType(stackType)
-{
- if (conf::pluginListX)
- resize(conf::pluginListX, conf::pluginListY, w(), h());
-
- list = new Fl_Scroll(8, 8, 476, 188);
- list->type(Fl_Scroll::VERTICAL);
- list->scrollbar.color(G_COLOR_GREY_2);
- list->scrollbar.selection_color(G_COLOR_GREY_4);
- list->scrollbar.labelcolor(G_COLOR_LIGHT_1);
- list->scrollbar.slider(G_CUSTOM_BORDER_BOX);
-
- list->begin();
- refreshList();
- list->end();
-
- end();
- set_non_modal();
-
- /* TODO - awful stuff... we should subclass into gdPluginListChannel and
- gdPluginListMaster */
-
- if (stackType == pluginHost::MASTER_OUT)
- label("Master Out Plugins");
- else
- if (stackType == pluginHost::MASTER_IN)
- label("Master In Plugins");
- else {
- string l = "Channel " + gu_toString(ch->index+1) + " Plugins";
- copy_label(l.c_str());
- }
-
- gu_setFavicon(this);
- show();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdPluginList::~gdPluginList()
-{
- conf::pluginListX = x();
- conf::pluginListY = y();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::cb_addPlugin(Fl_Widget *v, void *p) { ((gdPluginList*)p)->__cb_addPlugin(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::cb_refreshList(Fl_Widget *v, void *p)
-{
- /* note: this callback is fired by gdBrowser. Close its window first,
- * by calling the parent (pluginList) and telling it to delete its
- * subwindow (i.e. gdBrowser). */
-
- gdWindow *child = (gdWindow*) v;
- if (child->getParent() != nullptr)
- (child->getParent())->delSubWindow(child);
-
- /* finally refresh plugin list: void *p is a pointer to gdPluginList.
- * This callback works even when you click 'x' to close the window...
- * well, who cares */
-
- ((gdPluginList*)p)->refreshList();
- ((gdPluginList*)p)->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::__cb_addPlugin()
-{
- /* the usual callback that gdWindow adds to each subwindow in this case
- * is not enough, because when we close the browser the plugin list
- * must be redrawn. We have a special callback, cb_refreshList, which
- * we add to gdPluginChooser. It does exactly what we need. */
-
- gdPluginChooser *pc = new gdPluginChooser(conf::pluginChooserX,
- conf::pluginChooserY, conf::pluginChooserW, conf::pluginChooserH,
- stackType, ch);
- addSubWindow(pc);
- pc->callback(cb_refreshList, (void*)this); // 'this' refers to gdPluginList
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginList::refreshList()
-{
- /* delete the previous list */
-
- list->clear();
- list->scroll_to(0, 0);
-
- /* add new buttons, as many as the plugin in pluginHost::stack + 1,
- * the 'add new' button. Warning: if ch == nullptr we are working with
- * master in/master out stacks. */
-
- int numPlugins = pluginHost::countPlugins(stackType, ch);
- int i = 0;
-
- while (i<numPlugins) {
- Plugin *pPlugin = pluginHost::getPluginByIndex(i, stackType, ch);
- gdPlugin *gdp = new gdPlugin(this, pPlugin, list->x(), list->y()-list->yposition()+(i*24), 800);
- list->add(gdp);
- i++;
- }
-
- int addPlugY = numPlugins == 0 ? 90 : list->y()-list->yposition()+(i*24);
- addPlugin = new geButton(8, addPlugY, 452, 20, "-- add new plugin --");
- addPlugin->callback(cb_addPlugin, (void*)this);
- list->add(addPlugin);
-
- /* if num(plugins) > 7 make room for the side scrollbar.
- * Scrollbar.width = 20 + 4(margin) */
-
- if (i>7)
- size(492, h());
- else
- size(468, h());
-
- redraw();
-
- /* set 'full' flag to FX button */
-
- /* TODO - awful stuff... we should subclass into gdPluginListChannel and
- gdPluginListMaster */
-
- if (stackType == pluginHost::MASTER_OUT) {
- G_MainWin->mainIO->setMasterFxOutFull(
- pluginHost::countPlugins(stackType, ch) > 0);
- }
- else
- if (stackType == pluginHost::MASTER_IN) {
- G_MainWin->mainIO->setMasterFxInFull(
- pluginHost::countPlugins(stackType, ch) > 0);
- }
- else {
- ch->guiChannel->fx->status = pluginHost::countPlugins(stackType, ch) > 0;
- ch->guiChannel->fx->redraw();
- }
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdPlugin::gdPlugin(gdPluginList *gdp, Plugin *p, int X, int Y, int W)
- : Fl_Group(X, Y, W, 20), pParent(gdp), pPlugin (p)
-{
- begin();
- button = new geIdButton(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);
- end();
-
- button->copy_label(pPlugin->getName().c_str());
- button->callback(cb_openPluginWindow, (void*)this);
-
- program->callback(cb_setProgram, (void*)this);
-
- for (int i=0; i<pPlugin->getNumPrograms(); i++)
- program->add(gu_removeFltkChars(pPlugin->getProgramName(i)).c_str());
-
- if (program->size() == 0) {
- program->add("-- no programs --\0");
- program->deactivate();
- }
- else
- program->value(pPlugin->getCurrentProgram());
-
- bypass->callback(cb_setBypass, (void*)this);
- bypass->type(FL_TOGGLE_BUTTON);
- bypass->value(pPlugin->isBypassed() ? 0 : 1);
-
- shiftUp->callback(cb_shiftUp, (void*)this);
- shiftDown->callback(cb_shiftDown, (void*)this);
- remove->callback(cb_removePlugin, (void*)this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::cb_removePlugin (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_removePlugin(); }
-void gdPlugin::cb_openPluginWindow(Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_openPluginWindow(); }
-void gdPlugin::cb_setBypass (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_setBypass(); }
-void gdPlugin::cb_shiftUp (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_shiftUp(); }
-void gdPlugin::cb_shiftDown (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_shiftDown(); }
-void gdPlugin::cb_setProgram (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_setProgram(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_shiftUp()
-{
- /*nothing to do if there's only one plugin */
-
- if (pluginHost::countPlugins(pParent->stackType, pParent->ch) == 1)
- return;
-
- int pluginIndex = pluginHost::getPluginIndex(pPlugin->getId(),
- pParent->stackType, pParent->ch);
-
- if (pluginIndex == 0) // first of the stack, do nothing
- return;
-
- glue_swapPlugins(pParent->ch, pluginIndex, pluginIndex-1, pParent->stackType);
- pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_shiftDown()
-{
- /*nothing to do if there's only one plugin */
-
- if (pluginHost::countPlugins(pParent->stackType, pParent->ch) == 1)
- return;
-
- unsigned pluginIndex = pluginHost::getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
- unsigned stackSize = (pluginHost::getStack(pParent->stackType, pParent->ch))->size();
-
- if (pluginIndex == stackSize-1) // last one in the stack, do nothing
- return;
-
- glue_swapPlugins(pParent->ch, pluginIndex, pluginIndex+1, pParent->stackType);
- pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_removePlugin()
-{
- /* any subwindow linked to the plugin must be destroyed first */
-
- pParent->delSubWindow(pPlugin->getId());
- glue_freePlugin(pParent->ch, pPlugin->getId(), pParent->stackType);
- pParent->refreshList();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_openPluginWindow()
-{
- /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved
- * for the parent window 'add plugin'. */
-
- gdWindow *w;
- if (pPlugin->hasEditor()) {
- if (pPlugin->isEditorOpen()) {
- gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor but it's already visible\n");
- return;
- }
-
- int pwid = pPlugin->getId()+1;
-
- gu_log("[gdPlugin::__cb_openPluginWindow] plugin has editor, open window id=%d\n", pwid);
-
- if (pParent->hasWindow(pwid))
- pParent->delSubWindow(pwid);
- w = new gdPluginWindowGUI(pPlugin);
- w->setId(pwid);
- pParent->addSubWindow(w);
- }
- else {
- w = new gdPluginWindow(pPlugin);
- }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_setBypass()
-{
- pPlugin->toggleBypass();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPlugin::__cb_setProgram()
-{
- pPlugin->setCurrentProgram(program->value());
-}
-
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 GD_PLUGINLIST_H
-#define GD_PLUGINLIST_H
-
-#include <FL/Fl.H>
-#include <FL/Fl_Scroll.H>
-#include "window.h"
-
-
-class Plugin;
-class Channel;
-class geButton;
-class gdPluginList;
-class geIdButton;
-class geChoice;
-
-
-class gdPluginList : public gdWindow
-{
-private:
-
- geButton *addPlugin;
- Fl_Scroll *list;
-
- static void cb_addPlugin (Fl_Widget *v, void *p);
- inline void __cb_addPlugin();
-
-public:
-
- Channel *ch; // ch == nullptr ? masterOut
- int stackType;
-
- gdPluginList(int stackType, Channel *ch=nullptr);
- ~gdPluginList();
-
- /* special callback, passed to browser. When closed (i.e. plugin
- * has been selected) the same browser will refresh this window. */
-
- static void cb_refreshList(Fl_Widget*, void*);
-
- void refreshList();
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class gdPlugin : public Fl_Group
-{
-private:
-
- gdPluginList *pParent;
- Plugin *pPlugin;
-
- static void cb_removePlugin (Fl_Widget *v, void *p);
- static void cb_openPluginWindow (Fl_Widget *v, void *p);
- static void cb_setBypass (Fl_Widget *v, void *p);
- static void cb_shiftUp (Fl_Widget *v, void *p);
- static void cb_shiftDown (Fl_Widget *v, void *p);
- static void cb_setProgram (Fl_Widget *v, void *p);
- inline void __cb_removePlugin ();
- inline void __cb_openPluginWindow ();
- inline void __cb_setBypass ();
- inline void __cb_shiftUp ();
- inline void __cb_shiftDown ();
- inline void __cb_setProgram ();
-
-public:
-
- geIdButton *button;
- geChoice *program;
- geIdButton *bypass;
- geIdButton *shiftUp;
- geIdButton *shiftDown;
- geIdButton *remove;
-
- gdPlugin(gdPluginList *gdp, Plugin *p, int x, int y, int w);
-};
-
-#endif
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 <FL/Fl_Scroll.H>
-#include "../../utils/gui.h"
-#include "../../core/plugin.h"
-#include "../elems/basics/boxtypes.h"
-#include "../elems/basics/box.h"
-#include "../elems/basics/liquidScroll.h"
-#include "../elems/basics/slider.h"
-#include "gd_pluginWindow.h"
-
-
-using std::string;
-
-
-Parameter::Parameter(int paramIndex, Plugin *p, int X, int Y, int W)
- : Fl_Group(X, Y, W-24, 20), paramIndex(paramIndex), pPlugin(p)
-{
- begin();
-
- label = new geBox(x(), y(), 60, 20);
- label->copy_label(pPlugin->getParameterName(paramIndex).c_str());
- label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-
- slider = new geSlider(label->x()+label->w()+8, y(), W-200, 20);
- slider->value(pPlugin->getParameter(paramIndex));
- slider->callback(cb_setValue, (void *)this);
-
- value = new geBox(slider->x()+slider->w()+8, y(), 100, 20);
- value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
- value->box(G_CUSTOM_BORDER_BOX);
- updateValue();
-
- resizable(slider);
-
- end();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Parameter::cb_setValue(Fl_Widget *v, void *p) { ((Parameter*)p)->__cb_setValue(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Parameter::__cb_setValue()
-{
- pPlugin->setParameter(paramIndex, slider->value());
- updateValue();
- value->redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Parameter::updateValue()
-{
- string v = pPlugin->getParameterText(paramIndex) + " " +
- pPlugin->getParameterLabel(paramIndex);
- value->copy_label(v.c_str());
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-gdPluginWindow::gdPluginWindow(Plugin *p)
- : gdWindow(400, 156), pPlugin(p) // 350
-{
- set_non_modal();
-
- geLiquidScroll *list = new geLiquidScroll(8, 8, w()-16, h()-16);
- list->type(Fl_Scroll::VERTICAL_ALWAYS);
- list->begin();
-
- int numParams = pPlugin->getNumParameters();
- for (int i=0; i<numParams; i++)
- new Parameter(i, pPlugin, list->x(), list->y()+(i*24), list->w());
- list->end();
-
- end();
-
- label(pPlugin->getName().c_str());
-
- size_range(400, (24*1)+12);
- resizable(list);
-
- gu_setFavicon(this);
- show();
-}
-
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 GD_PLUGIN_WINDOW_H
-#define GD_PLUGIN_WINDOW_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "window.h"
-
-
-class Plugin;
-class geBox;
-class geSlider;
-
-
-class gdPluginWindow : public gdWindow
-{
-private:
-
- Plugin *pPlugin;
-
-public:
-
- int id;
-
- gdPluginWindow(Plugin *pPlugin);
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-class Parameter : public Fl_Group
-{
-private:
-
- int paramIndex;
- Plugin *pPlugin;
-
- static void cb_setValue(Fl_Widget *v, void *p);
- inline void __cb_setValue();
-
- void updateValue();
-
-public:
-
- geBox *label;
- geSlider *slider;
- geBox *value;
-
- Parameter(int paramIndex, Plugin *p, int x, int y, int w);
-};
-
-
-#endif
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 <FL/x.H>
-#include "../../utils/log.h"
-#include "../../utils/gui.h"
-#include "../../core/pluginHost.h"
-#include "../../core/plugin.h"
-#include "../../core/const.h"
-#include "gd_pluginWindowGUI.h"
-
-#ifdef __APPLE__
-#import "../../utils/cocoa.h" // objective-c
-#endif
-
-
-using namespace giada::m;
-
-
-gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
- : gdWindow(450, 300), pPlugin(pPlugin)
-{
- show();
-
-#ifndef __APPLE__
-
- Fl::check();
-
-#endif
-
- gu_log("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
- (void*) this, (void*) fl_xid(this));
-
-#if defined(__APPLE__)
-
- void *cocoaWindow = (void*) fl_xid(this);
- cocoa_setWindowSize(cocoaWindow, pPlugin->getEditorW(), pPlugin->getEditorH());
- pPlugin->showEditor(cocoa_getViewFromWindow(cocoaWindow));
-
-#else
-
- pPlugin->showEditor((void*) fl_xid(this));
-
-#endif
-
- int pluginW = pPlugin->getEditorW();
- int pluginH = pPlugin->getEditorH();
-
- resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH);
-
- Fl::add_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
-
- copy_label(pPlugin->getName().c_str());
-
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginWindowGUI::cb_close(Fl_Widget *v, void *p) { ((gdPluginWindowGUI*)p)->__cb_close(); }
-void gdPluginWindowGUI::cb_refresh(void *data) { ((gdPluginWindowGUI*)data)->__cb_refresh(); }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginWindowGUI::__cb_close()
-{
- Fl::remove_timeout(cb_refresh);
- pPlugin->closeEditor();
- gu_log("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gdPluginWindowGUI::__cb_refresh()
-{
- pluginHost::runDispatchLoop();
- Fl::repeat_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-gdPluginWindowGUI::~gdPluginWindowGUI()
-{
- __cb_close();
-}
-
-#endif // #ifdef WITH_VST
+++ /dev/null
-
-/* ---------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * gd_pluginWindowGUI
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 GD_PLUGIN_WINDOW_GUI_H
-#define GD_PLUGIN_WINDOW_GUI_H
-
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "window.h"
-#if defined(__APPLE__)
- #include <Carbon/Carbon.h>
-#endif
-
-
-class Plugin;
-
-
-class gdPluginWindowGUI : public gdWindow
-{
-private:
-
- Plugin *pPlugin;
-
- static void cb_close (Fl_Widget *v, void *p);
- static void cb_refresh (void *data);
- inline void __cb_close ();
- inline void __cb_refresh();
-
-public:
-
- gdPluginWindowGUI(Plugin *pPlugin);
- ~gdPluginWindowGUI();
-};
-
-
-#endif // include guard
-
-#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "../../glue/plugin.h"
+#include "../../utils/gui.h"
+#include "../../core/channel.h"
+#include "../../core/conf.h"
+#include "../../core/pluginHost.h"
+#include "../elems/plugin/pluginBrowser.h"
+#include "../elems/basics/button.h"
+#include "../elems/basics/choice.h"
+#include "../elems/basics/box.h"
+#include "pluginChooser.h"
+
+
+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)
+{
+ /* top area */
+ Fl_Group *group_top = new Fl_Group(8, 8, w()-16, 20);
+ sortMethod = new geChoice(group_top->x() + 45, group_top->y(), 100, 20, "Sort by");
+ geBox *b1 = new geBox(sortMethod->x()+sortMethod->w(), group_top->y(), 100, 20); // spacer window border <-> menu
+ group_top->resizable(b1);
+ group_top->end();
+
+ /* center browser */
+ browser = new gePluginBrowser(8, 36, w()-16, h()-70);
+
+ /* ok/cancel buttons */
+ Fl_Group *group_btn = new Fl_Group(8, browser->y()+browser->h()+8, w()-16, h()-browser->h()-16);
+ geBox *b2 = new geBox(8, browser->y()+browser->h(), 100, 20); // spacer window border <-> buttons
+ addBtn = new geButton(w()-88, group_btn->y(), 80, 20, "Add");
+ cancelBtn = new geButton(addBtn->x()-88, group_btn->y(), 80, 20, "Cancel");
+ group_btn->resizable(b2);
+ group_btn->end();
+
+ end();
+
+ sortMethod->add("Name");
+ sortMethod->add("Category");
+ sortMethod->add("Manufacturer");
+ sortMethod->callback(cb_sort, (void*) this);
+ sortMethod->value(conf::pluginSortMethod);
+
+ addBtn->callback(cb_add, (void*) this);
+ addBtn->shortcut(FL_Enter);
+ cancelBtn->callback(cb_close, (void*) this);
+
+ resizable(browser);
+ gu_setFavicon(this);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdPluginChooser::~gdPluginChooser()
+{
+ conf::pluginChooserX = x();
+ conf::pluginChooserY = y();
+ conf::pluginChooserW = w();
+ conf::pluginChooserH = h();
+ conf::pluginSortMethod = sortMethod->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginChooser::cb_close(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_close(); }
+void gdPluginChooser::cb_add(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_add(); }
+void gdPluginChooser::cb_sort(Fl_Widget *v, void *p) { ((gdPluginChooser*)p)->__cb_sort(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginChooser::__cb_close()
+{
+ do_callback();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginChooser::__cb_sort()
+{
+ pluginHost::sortPlugins(sortMethod->value());
+ browser->refresh();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginChooser::__cb_add()
+{
+ int index = browser->value() - 3; // subtract header lines
+ if (index < 0)
+ return;
+ plugin::addPlugin(ch, index, stackType);
+ do_callback();
+}
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GD_PLUGIN_CHOOSER_H
+#define GD_PLUGIN_CHOOSER_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include "window.h"
+
+
+class Channel;
+class geChoice;
+class geButton;
+class geButton;
+class gePluginBrowser;
+
+
+class gdPluginChooser : public gdWindow
+{
+private:
+
+ Channel *ch; // ch == nullptr ? masterOut
+ int stackType;
+
+ geChoice *sortMethod;
+ geButton *addBtn;
+ geButton *cancelBtn;
+ gePluginBrowser *browser;
+
+ static void cb_close(Fl_Widget *w, void *p);
+ static void cb_add (Fl_Widget *w, void *p);
+ static void cb_sort (Fl_Widget *w, void *p);
+ inline void __cb_close();
+ inline void __cb_add ();
+ inline void __cb_sort ();
+
+public:
+
+ gdPluginChooser(int x, int y, int w, int h, int stackType, Channel *ch=nullptr);
+ ~gdPluginChooser();
+};
+
+
+#endif
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "../../utils/gui.h"
+#include "../../utils/fs.h"
+#include "../../core/conf.h"
+#include "../../core/const.h"
+#include "../../core/graphics.h"
+#include "../../core/pluginHost.h"
+#include "../../core/plugin.h"
+#include "../../core/mixer.h"
+#include "../../core/channel.h"
+#include "../../glue/plugin.h"
+#include "../../utils/log.h"
+#include "../../utils/string.h"
+#include "../elems/basics/boxtypes.h"
+#include "../elems/basics/idButton.h"
+#include "../elems/basics/statusButton.h"
+#include "../elems/basics/choice.h"
+#include "../elems/mainWindow/mainIO.h"
+#include "../elems/mainWindow/keyboard/channel.h"
+#include "pluginChooser.h"
+#include "pluginWindow.h"
+#include "pluginWindowGUI.h"
+#include "gd_mainWindow.h"
+#include "pluginList.h"
+
+
+extern gdMainWindow* G_MainWin;
+
+
+using std::string;
+using namespace giada::m;
+using namespace giada::c;
+
+
+gdPluginList::gdPluginList(int stackType, Channel* ch)
+ : gdWindow(468, 204), ch(ch), stackType(stackType)
+{
+ if (conf::pluginListX)
+ resize(conf::pluginListX, conf::pluginListY, w(), h());
+
+ list = new Fl_Scroll(8, 8, 476, 188);
+ list->type(Fl_Scroll::VERTICAL);
+ list->scrollbar.color(G_COLOR_GREY_2);
+ list->scrollbar.selection_color(G_COLOR_GREY_4);
+ list->scrollbar.labelcolor(G_COLOR_LIGHT_1);
+ list->scrollbar.slider(G_CUSTOM_BORDER_BOX);
+
+ list->begin();
+ refreshList();
+ list->end();
+
+ end();
+ set_non_modal();
+
+ /* TODO - awful stuff... we should subclass into gdPluginListChannel and
+ gdPluginListMaster */
+
+ if (stackType == pluginHost::MASTER_OUT)
+ label("Master Out Plugins");
+ else
+ if (stackType == pluginHost::MASTER_IN)
+ label("Master In Plugins");
+ else {
+ string l = "Channel " + gu_toString(ch->index+1) + " Plugins";
+ copy_label(l.c_str());
+ }
+
+ gu_setFavicon(this);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdPluginList::~gdPluginList()
+{
+ conf::pluginListX = x();
+ conf::pluginListY = y();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::cb_addPlugin(Fl_Widget* v, void* p) { ((gdPluginList*)p)->__cb_addPlugin(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::cb_refreshList(Fl_Widget* v, void* p)
+{
+ /* note: this callback is fired by gdBrowser. Close its window first,
+ * by calling the parent (pluginList) and telling it to delete its
+ * subwindow (i.e. gdBrowser). */
+
+ gdWindow *child = (gdWindow*) v;
+ if (child->getParent() != nullptr)
+ (child->getParent())->delSubWindow(child);
+
+ /* finally refresh plugin list: void *p is a pointer to gdPluginList.
+ * This callback works even when you click 'x' to close the window...
+ * well, who cares */
+
+ ((gdPluginList*)p)->refreshList();
+ ((gdPluginList*)p)->redraw();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::__cb_addPlugin()
+{
+ /* the usual callback that gdWindow adds to each subwindow in this case
+ * is not enough, because when we close the browser the plugin list
+ * must be redrawn. We have a special callback, cb_refreshList, which
+ * we add to gdPluginChooser. It does exactly what we need. */
+
+ gdPluginChooser* pc = new gdPluginChooser(conf::pluginChooserX,
+ conf::pluginChooserY, conf::pluginChooserW, conf::pluginChooserH,
+ stackType, ch);
+ addSubWindow(pc);
+ pc->callback(cb_refreshList, (void*)this); // 'this' refers to gdPluginList
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginList::refreshList()
+{
+ /* delete the previous list */
+
+ list->clear();
+ list->scroll_to(0, 0);
+
+ /* add new buttons, as many as the plugin in pluginHost::stack + 1,
+ * the 'add new' button. Warning: if ch == nullptr we are working with
+ * master in/master out stacks. */
+
+ int numPlugins = pluginHost::countPlugins(stackType, ch);
+ int i = 0;
+
+ while (i<numPlugins) {
+ Plugin *pPlugin = pluginHost::getPluginByIndex(i, stackType, ch);
+ gdPlugin *gdp = new gdPlugin(this, pPlugin, list->x(), list->y()-list->yposition()+(i*24), 800);
+ list->add(gdp);
+ i++;
+ }
+
+ int addPlugY = numPlugins == 0 ? 90 : list->y()-list->yposition()+(i*24);
+ addPlugin = new geButton(8, addPlugY, 452, 20, "-- add new plugin --");
+ addPlugin->callback(cb_addPlugin, (void*)this);
+ list->add(addPlugin);
+
+ /* if num(plugins) > 7 make room for the side scrollbar.
+ * Scrollbar.width = 20 + 4(margin) */
+
+ if (i>7)
+ size(492, h());
+ else
+ size(468, h());
+
+ redraw();
+
+ /* set 'full' flag to FX button */
+
+ /* TODO - awful stuff... we should subclass into gdPluginListChannel and
+ gdPluginListMaster */
+
+ if (stackType == pluginHost::MASTER_OUT) {
+ G_MainWin->mainIO->setMasterFxOutFull(
+ pluginHost::countPlugins(stackType, ch) > 0);
+ }
+ else
+ if (stackType == pluginHost::MASTER_IN) {
+ G_MainWin->mainIO->setMasterFxInFull(
+ pluginHost::countPlugins(stackType, ch) > 0);
+ }
+ else {
+ ch->guiChannel->fx->status = pluginHost::countPlugins(stackType, ch) > 0;
+ ch->guiChannel->fx->redraw();
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+gdPlugin::gdPlugin(gdPluginList* gdp, Plugin* p, int X, int Y, int W)
+ : Fl_Group(X, Y, W, 20), pParent(gdp), pPlugin (p)
+{
+ begin();
+ button = new geIdButton(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);
+ end();
+
+ button->copy_label(pPlugin->getName().c_str());
+ button->callback(cb_openPluginWindow, (void*)this);
+
+ program->callback(cb_setProgram, (void*)this);
+
+ for (int i=0; i<pPlugin->getNumPrograms(); i++)
+ program->add(gu_removeFltkChars(pPlugin->getProgramName(i)).c_str());
+
+ if (program->size() == 0) {
+ program->add("-- no programs --\0");
+ program->deactivate();
+ }
+ else
+ program->value(pPlugin->getCurrentProgram());
+
+ bypass->callback(cb_setBypass, (void*)this);
+ bypass->type(FL_TOGGLE_BUTTON);
+ bypass->value(pPlugin->isBypassed() ? 0 : 1);
+
+ shiftUp->callback(cb_shiftUp, (void*)this);
+ shiftDown->callback(cb_shiftDown, (void*)this);
+ remove->callback(cb_removePlugin, (void*)this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::cb_removePlugin (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_removePlugin(); }
+void gdPlugin::cb_openPluginWindow(Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_openPluginWindow(); }
+void gdPlugin::cb_setBypass (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_setBypass(); }
+void gdPlugin::cb_shiftUp (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_shiftUp(); }
+void gdPlugin::cb_shiftDown (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_shiftDown(); }
+void gdPlugin::cb_setProgram (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_setProgram(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_shiftUp()
+{
+ /*nothing to do if there's only one plugin */
+
+ if (pluginHost::countPlugins(pParent->stackType, pParent->ch) == 1)
+ return;
+
+ int pluginIndex = pluginHost::getPluginIndex(pPlugin->getId(),
+ pParent->stackType, pParent->ch);
+
+ if (pluginIndex == 0) // first of the stack, do nothing
+ return;
+
+ plugin::swapPlugins(pParent->ch, pluginIndex, pluginIndex-1, pParent->stackType);
+ pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_shiftDown()
+{
+ /*nothing to do if there's only one plugin */
+
+ if (pluginHost::countPlugins(pParent->stackType, pParent->ch) == 1)
+ return;
+
+ unsigned pluginIndex = pluginHost::getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch);
+ unsigned stackSize = (pluginHost::getStack(pParent->stackType, pParent->ch))->size();
+
+ if (pluginIndex == stackSize-1) // last one in the stack, do nothing
+ return;
+
+ plugin::swapPlugins(pParent->ch, pluginIndex, pluginIndex+1, pParent->stackType);
+ pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_removePlugin()
+{
+ /* any subwindow linked to the plugin must be destroyed first */
+
+ pParent->delSubWindow(pPlugin->getId());
+ plugin::freePlugin(pParent->ch, pPlugin->getId(), pParent->stackType);
+ pParent->refreshList();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_openPluginWindow()
+{
+ /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved
+ * for the parent window 'add plugin'. */
+
+ int pwid = pPlugin->getId() + 1;
+
+ gdWindow* w;
+ if (pPlugin->hasEditor()) {
+ if (pPlugin->isEditorOpen()) {
+ gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has editor but it's already visible\n");
+ pParent->getChild(pwid)->show(); // Raise it to top
+ return;
+ }
+ gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has editor, window id=%d\n", pwid);
+ w = new gdPluginWindowGUI(pPlugin);
+ }
+ else
+ w = new gdPluginWindow(pPlugin);
+
+ gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has no editor, window id=%d\n", pwid);
+
+ if (pParent->hasWindow(pwid))
+ pParent->delSubWindow(pwid);
+ w->setId(pwid);
+ pParent->addSubWindow(w);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_setBypass()
+{
+ pPlugin->toggleBypass();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPlugin::__cb_setProgram()
+{
+ pPlugin->setCurrentProgram(program->value());
+}
+
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GD_PLUGINLIST_H
+#define GD_PLUGINLIST_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include "window.h"
+
+
+class Plugin;
+class Channel;
+class geButton;
+class gdPluginList;
+class geIdButton;
+class geChoice;
+
+
+class gdPluginList : public gdWindow
+{
+private:
+
+ geButton *addPlugin;
+ Fl_Scroll *list;
+
+ static void cb_addPlugin (Fl_Widget *v, void *p);
+ inline void __cb_addPlugin();
+
+public:
+
+ Channel *ch; // ch == nullptr ? masterOut
+ int stackType;
+
+ gdPluginList(int stackType, Channel *ch=nullptr);
+ ~gdPluginList();
+
+ /* special callback, passed to browser. When closed (i.e. plugin
+ * has been selected) the same browser will refresh this window. */
+
+ static void cb_refreshList(Fl_Widget*, void*);
+
+ void refreshList();
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+
+class gdPlugin : public Fl_Group
+{
+private:
+
+ gdPluginList *pParent;
+ Plugin *pPlugin;
+
+ static void cb_removePlugin (Fl_Widget *v, void *p);
+ static void cb_openPluginWindow (Fl_Widget *v, void *p);
+ static void cb_setBypass (Fl_Widget *v, void *p);
+ static void cb_shiftUp (Fl_Widget *v, void *p);
+ static void cb_shiftDown (Fl_Widget *v, void *p);
+ static void cb_setProgram (Fl_Widget *v, void *p);
+ inline void __cb_removePlugin ();
+ inline void __cb_openPluginWindow ();
+ inline void __cb_setBypass ();
+ inline void __cb_shiftUp ();
+ inline void __cb_shiftDown ();
+ inline void __cb_setProgram ();
+
+public:
+
+ geIdButton *button;
+ geChoice *program;
+ geIdButton *bypass;
+ geIdButton *shiftUp;
+ geIdButton *shiftDown;
+ geIdButton *remove;
+
+ gdPlugin(gdPluginList *gdp, Plugin *p, int x, int y, int w);
+};
+
+#endif
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <FL/fl_draw.H>
+#include "../../utils/gui.h"
+#include "../../core/plugin.h"
+#include "../../core/const.h"
+#include "../elems/basics/liquidScroll.h"
+#include "../elems/plugin/pluginParameter.h"
+#include "pluginWindow.h"
+
+
+gdPluginWindow::gdPluginWindow(Plugin* p)
+ : gdWindow(450, 156), m_plugin(p)
+{
+ set_non_modal();
+
+ m_list = new geLiquidScroll(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN,
+ w()-(G_GUI_OUTER_MARGIN*2), h()-(G_GUI_OUTER_MARGIN*2));
+
+ m_list->type(Fl_Scroll::VERTICAL_ALWAYS);
+ m_list->begin();
+ int labelWidth = getLabelWidth();
+ int numParams = m_plugin->getNumParameters();
+ for (int i=0; i<numParams; i++) {
+ int py = m_list->y() + (i * (G_GUI_UNIT + G_GUI_INNER_MARGIN));
+ int pw = m_list->w() - m_list->scrollbar_size() - (G_GUI_OUTER_MARGIN*3);
+ new gePluginParameter(i, m_plugin, m_list->x(), py, pw, labelWidth);
+ }
+ m_list->end();
+
+ end();
+
+ label(m_plugin->getName().c_str());
+
+ size_range(450, (G_GUI_UNIT + (G_GUI_OUTER_MARGIN*2)));
+ resizable(m_list);
+
+ gu_setFavicon(this);
+ show();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginWindow::updateParameter(int index, bool changeSlider)
+{
+ static_cast<gePluginParameter*>(m_list->child(index))->update(changeSlider);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gdPluginWindow::getLabelWidth() const
+{
+ int width = 0;
+ int numParams = m_plugin->getNumParameters();
+ for (int i=0; i<numParams; i++) {
+ int wl = 0, hl = 0;
+ fl_measure(m_plugin->getParameterName(i).c_str(), wl, hl);
+ if (wl > width)
+ width = wl;
+ }
+ return width;
+}
+
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GD_PLUGIN_WINDOW_H
+#define GD_PLUGIN_WINDOW_H
+
+
+#include "window.h"
+
+
+class Plugin;
+class geBox;
+class geSlider;
+class geLiquidScroll;
+
+
+class gdPluginWindow : public gdWindow
+{
+private:
+
+ Plugin* m_plugin;
+
+ geLiquidScroll* m_list;
+
+ int getLabelWidth() const;
+
+public:
+
+ gdPluginWindow(Plugin* p);
+
+ void updateParameter(int index, bool changeSlider=false);
+};
+
+
+#endif
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <FL/x.H>
+#include "../../utils/log.h"
+#include "../../utils/gui.h"
+#include "../../core/pluginHost.h"
+#include "../../core/plugin.h"
+#include "../../core/const.h"
+#include "pluginWindowGUI.h"
+
+#ifdef __APPLE__
+#import "../../utils/cocoa.h" // objective-c
+#endif
+
+
+using namespace giada::m;
+
+
+gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin)
+ : gdWindow(450, 300), pPlugin(pPlugin)
+{
+ show();
+
+#ifndef __APPLE__
+
+ Fl::check();
+
+#endif
+
+ gu_log("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
+ (void*) this, (void*) fl_xid(this));
+
+#if defined(__APPLE__)
+
+ void *cocoaWindow = (void*) fl_xid(this);
+ cocoa_setWindowSize(cocoaWindow, pPlugin->getEditorW(), pPlugin->getEditorH());
+ pPlugin->showEditor(cocoa_getViewFromWindow(cocoaWindow));
+
+#else
+
+ pPlugin->showEditor((void*) fl_xid(this));
+
+#endif
+
+ int pluginW = pPlugin->getEditorW();
+ int pluginH = pPlugin->getEditorH();
+
+ resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH);
+
+ Fl::add_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
+
+ copy_label(pPlugin->getName().c_str());
+
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginWindowGUI::cb_close(Fl_Widget *v, void *p) { ((gdPluginWindowGUI*)p)->__cb_close(); }
+void gdPluginWindowGUI::cb_refresh(void *data) { ((gdPluginWindowGUI*)data)->__cb_refresh(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginWindowGUI::__cb_close()
+{
+ Fl::remove_timeout(cb_refresh);
+ pPlugin->closeEditor();
+ gu_log("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdPluginWindowGUI::__cb_refresh()
+{
+ pluginHost::runDispatchLoop();
+ Fl::repeat_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+gdPluginWindowGUI::~gdPluginWindowGUI()
+{
+ __cb_close();
+}
+
+#endif // #ifdef WITH_VST
--- /dev/null
+
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * gd_pluginWindowGUI
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GD_PLUGIN_WINDOW_GUI_H
+#define GD_PLUGIN_WINDOW_GUI_H
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "window.h"
+#if defined(__APPLE__)
+ #include <Carbon/Carbon.h>
+#endif
+
+
+class Plugin;
+
+
+class gdPluginWindowGUI : public gdWindow
+{
+private:
+
+ Plugin *pPlugin;
+
+ static void cb_close (Fl_Widget *v, void *p);
+ static void cb_refresh (void *data);
+ inline void __cb_close ();
+ inline void __cb_refresh();
+
+public:
+
+ gdPluginWindowGUI(Plugin *pPlugin);
+ ~gdPluginWindowGUI();
+};
+
+
+#endif // include guard
+
+#endif // #ifdef WITH_VST
#include "../elems/sampleEditor/panTool.h"
#include "../elems/sampleEditor/pitchTool.h"
#include "../elems/sampleEditor/rangeTool.h"
+#include "../elems/sampleEditor/shiftTool.h"
#include "../elems/mainWindow/keyboard/channel.h"
#include "gd_warnings.h"
#include "sampleEditor.h"
{
Fl_Group* upperBar = createUpperBar();
- waveTools = new geWaveTools(8, upperBar->y()+upperBar->h()+8, w()-16, h()-128,
- ch);
+ waveTools = new geWaveTools(G_GUI_OUTER_MARGIN, upperBar->y()+upperBar->h()+G_GUI_OUTER_MARGIN,
+ w()-16, h()-128, ch);
- Fl_Group* bottomBar = createBottomBar(8, waveTools->y()+waveTools->h()+8,
+ Fl_Group* bottomBar = createBottomBar(G_GUI_OUTER_MARGIN, waveTools->y()+waveTools->h()+G_GUI_OUTER_MARGIN,
h()-waveTools->h()-upperBar->h()-32);
add(upperBar);
gu_setFavicon(this);
set_non_modal();
- copy_label(ch->wave->getName().c_str());
+ copy_label(ch->getName().c_str());
size_range(720, 480);
if (conf::sampleEditorX)
Fl_Group* gdSampleEditor::createUpperBar()
{
- Fl_Group* g = new Fl_Group(8, 8, w()-16, 20);
+ Fl_Group* g = new Fl_Group(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w()-16, G_GUI_UNIT);
g->begin();
- grid = new geChoice(g->x(), g->y(), 50, 20);
+ grid = new geChoice(g->x(), g->y(), 50, G_GUI_UNIT);
snap = new geCheck(grid->x()+grid->w()+4, g->y()+3, 12, 12, "Snap");
- sep1 = new geBox(snap->x()+snap->w()+4, g->y(), 506, 20);
- zoomOut = new geButton(sep1->x()+sep1->w()+4, g->y(), 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
- zoomIn = new geButton(zoomOut->x()+zoomOut->w()+4, g->y(), 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+ sep1 = new geBox(snap->x()+snap->w()+4, g->y(), 506, G_GUI_UNIT);
+ zoomOut = new geButton(sep1->x()+sep1->w()+4, g->y(), G_GUI_UNIT, G_GUI_UNIT, "", zoomOutOff_xpm, zoomOutOn_xpm);
+ zoomIn = new geButton(zoomOut->x()+zoomOut->w()+4, g->y(), G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
g->end();
g->resizable(sep1);
pitchTool = new gePitchTool(g->x(), panTool->y()+panTool->h()+8, ch);
rangeTool = new geRangeTool(g->x(), pitchTool->y()+pitchTool->h()+8, ch);
- reload = new geButton(g->x()+g->w()-70, rangeTool->y(), 70, 20, "Reload");
+ shiftTool = new geShiftTool(rangeTool->x()+rangeTool->w()+4, pitchTool->y()+pitchTool->h()+8, ch);
+ reload = new geButton(g->x()+g->w()-70, shiftTool->y(), 70, 20, "Reload");
g->end();
if (ch->wave->isLogical()) // Logical samples (aka takes) cannot be reloaded.
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::cb_reload (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_reload(); }
-void gdSampleEditor::cb_zoomIn (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_zoomIn(); }
-void gdSampleEditor::cb_zoomOut (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_zoomOut(); }
-void gdSampleEditor::cb_changeGrid (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_changeGrid(); }
-void gdSampleEditor::cb_enableSnap (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_enableSnap(); }
-void gdSampleEditor::cb_togglePreview(Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_togglePreview(); }
-void gdSampleEditor::cb_rewindPreview(Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->__cb_rewindPreview(); }
+void gdSampleEditor::cb_reload (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_reload(); }
+void gdSampleEditor::cb_zoomIn (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_zoomIn(); }
+void gdSampleEditor::cb_zoomOut (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_zoomOut(); }
+void gdSampleEditor::cb_changeGrid (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_changeGrid(); }
+void gdSampleEditor::cb_enableSnap (Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_enableSnap(); }
+void gdSampleEditor::cb_togglePreview(Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_togglePreview(); }
+void gdSampleEditor::cb_rewindPreview(Fl_Widget* w, void* p) { ((gdSampleEditor*)p)->cb_rewindPreview(); }
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_enableSnap()
+void gdSampleEditor::cb_enableSnap()
{
waveTools->waveform->setSnap(!waveTools->waveform->getSnap());
}
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_togglePreview()
+void gdSampleEditor::cb_togglePreview()
{
if (play->value())
sampleEditor::setPreview(ch, G_PREVIEW_NONE);
}
-void gdSampleEditor::__cb_rewindPreview()
+void gdSampleEditor::cb_rewindPreview()
{
sampleEditor::rewindPreview(ch);
}
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_reload()
+void gdSampleEditor::cb_reload()
{
/* TODO - move to glue::sampleEditor */
if (!gdConfirmWin("Warning", "Reload sample: are you sure?"))
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_zoomIn()
+void gdSampleEditor::cb_zoomIn()
{
waveTools->waveform->setZoom(-1);
waveTools->redraw();
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_zoomOut()
+void gdSampleEditor::cb_zoomOut()
{
waveTools->waveform->setZoom(0);
waveTools->redraw();
/* -------------------------------------------------------------------------- */
-void gdSampleEditor::__cb_changeGrid()
+void gdSampleEditor::cb_changeGrid()
{
waveTools->waveform->setGridLevel(atoi(grid->text()));
}
class gePanTool;
class gePitchTool;
class geRangeTool;
+class geSampleTool;
+class geShiftTool;
class geChoice;
class geCheck;
class geBox;
static void cb_enableSnap(Fl_Widget* w, void* p);
static void cb_togglePreview(Fl_Widget* w, void* p);
static void cb_rewindPreview(Fl_Widget* w, void* p);
- void __cb_reload();
- void __cb_zoomIn();
- void __cb_zoomOut();
- void __cb_changeGrid();
- void __cb_enableSnap();
- void __cb_togglePreview();
- void __cb_rewindPreview();
+ void cb_reload();
+ void cb_zoomIn();
+ void cb_zoomOut();
+ void cb_changeGrid();
+ void cb_enableSnap();
+ void cb_togglePreview();
+ void cb_rewindPreview();
public:
gePitchTool* pitchTool;
geRangeTool* rangeTool;
+ geShiftTool* shiftTool;
geButton* reload;
geButton* play;
/* cb_window_closer
* callback for when closing windows. Deletes the widget (delete). */
-void __cb_window_closer(Fl_Widget *v, void *p);
+void __cb_window_closer(Fl_Widget* v, void* p);
class gdWindow : public Fl_Double_Window
{
protected:
- std::vector <gdWindow*> subWindows;
+ std::vector<gdWindow*> subWindows;
int id;
- gdWindow *parent;
+ gdWindow* parent;
public:
- gdWindow(int x, int y, int w, int h, const char *title=0, int id=0);
- gdWindow(int w, int h, const char *title=0, int id=0);
+ gdWindow(int x, int y, int w, int h, const char* title=0, int id=0);
+ gdWindow(int w, int h, const char* title=0, int id=0);
~gdWindow();
- static void cb_closeChild(Fl_Widget *v, void *p);
+ static void cb_closeChild(Fl_Widget* v, void* p);
- void addSubWindow(gdWindow *w);
- void delSubWindow(gdWindow *w);
+ void addSubWindow(gdWindow* w);
+ void delSubWindow(gdWindow* w);
void delSubWindow(int id);
int getId();
void setId(int id);
void debug();
- void setParent(gdWindow *);
- gdWindow *getParent();
- gdWindow *getChild(int id);
+ void setParent(gdWindow* w);
+ gdWindow* getParent();
+ gdWindow* getChild(int id);
/* hasWindow
* true if the window with id 'id' exists in the stack. */
#include "liquidScroll.h"
-geLiquidScroll::geLiquidScroll(int x, int y, int w, int h, const char *l)
- : Fl_Scroll(x, y, w, h, l)
+geLiquidScroll::geLiquidScroll(int x, int y, int w, int h, const char* l)
+ : Fl_Scroll(x, y, w, h, l)
{
- type(Fl_Scroll::VERTICAL);
- scrollbar.color(G_COLOR_GREY_2);
- scrollbar.selection_color(G_COLOR_GREY_4);
- scrollbar.labelcolor(G_COLOR_LIGHT_1);
- scrollbar.slider(G_CUSTOM_BORDER_BOX);
+ type(Fl_Scroll::VERTICAL);
+ scrollbar.color(G_COLOR_GREY_2);
+ scrollbar.selection_color(G_COLOR_GREY_4);
+ scrollbar.labelcolor(G_COLOR_LIGHT_1);
+ scrollbar.slider(G_CUSTOM_BORDER_BOX);
}
void geLiquidScroll::resize(int X, int Y, int W, int H)
{
- int nc = children()-2; // skip hscrollbar and vscrollbar
- for ( int t=0; t<nc; t++) { // tell children to resize to our new width
- Fl_Widget *c = child(t);
- c->resize(c->x(), c->y(), W-24, c->h()); // W-24: leave room for scrollbar
- }
- init_sizes(); // tell scroll children changed in size
- Fl_Scroll::resize(X,Y,W,H);
+ int nc = children()-2; // skip hscrollbar and vscrollbar
+ for ( int t=0; t<nc; t++) { // tell children to resize to our new width
+ Fl_Widget* c = child(t);
+ c->resize(c->x(), c->y(), W-24, c->h()); // W-24: leave room for scrollbar
+ }
+ init_sizes(); // tell scroll children changed in size
+ Fl_Scroll::resize(X,Y,W,H);
}
: Fl_Group(X, Y, W, H, "Sound System")
{
begin();
- soundsys = new geChoice(x()+92, y()+9, 253, 20, "System");
- buffersize = new geChoice(x()+92, y()+37, 55, 20, "Buffer size");
- samplerate = new geChoice(x()+290, y()+37, 55, 20, "Sample rate");
- sounddevOut = new geChoice(x()+92, y()+65, 225, 20, "Output device");
- devOutInfo = new geButton (x()+325, y()+65, 20, 20, "?");
- channelsOut = new geChoice(x()+92, y()+93, 55, 20, "Output channels");
- limitOutput = new geCheck (x()+155, y()+97, 55, 20, "Limit output");
- sounddevIn = new geChoice(x()+92, y()+121, 225, 20, "Input device");
- devInInfo = new geButton (x()+325, y()+121, 20, 20, "?");
- channelsIn = new geChoice(x()+92, y()+149, 55, 20, "Input channels");
- delayComp = new geInput (x()+290, y()+149, 55, 20, "Rec delay comp.");
- rsmpQuality = new geChoice(x()+92, y()+177, 253, 20, "Resampling");
+ 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.");
end();
: Fl_Group(X, Y, W, H, "MIDI")
{
begin();
- system = new geChoice(x()+92, y()+9, 253, 20, "System");
- portOut = new geChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port");
- portIn = new geChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port");
- noNoteOff = new geCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff");
- midiMap = new geChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map");
- sync = new geChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync");
- new geBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect.");
+ system = new geChoice(x()+w()-250, y()+9, 250, 20, "System");
+ portOut = new geChoice(x()+w()-250, system->y()+system->h()+8, 250, 20, "Output port");
+ portIn = new geChoice(x()+w()-250, portOut->y()+portOut->h()+8, 250, 20, "Input port");
+ noNoteOff = new geCheck (x()+w()-250, portIn->y()+portIn->h()+8, 230, 20, "Device does not send NoteOff");
+ midiMap = new geChoice(x()+w()-250, noNoteOff->y()+noNoteOff->h(), 250, 20, "Output Midi Map");
+ sync = new geChoice(x()+w()-250, midiMap->y()+midiMap->h()+8, 250, 20, "Sync");
+ new geBox(x(), sync->y()+sync->h()+8, w(), h()-150, "Restart Giada for the changes to take effect.");
end();
labelsize(G_GUI_FONT_SIZE_BASE);
: Fl_Group(X, Y, W, H, "Misc")
{
begin();
- debugMsg = new geChoice(x()+92, y()+9, 253, 20, "Debug messages");
+ debugMsg = new geChoice(x()+w()-230, y()+9, 230, 20, "Debug messages");
end();
debugMsg->add("(disabled)");
#include "../../../../utils/gui.h"
#include "../../../../glue/channel.h"
#include "../../../dialogs/gd_mainWindow.h"
-#include "../../../dialogs/gd_pluginList.h"
+#include "../../../dialogs/pluginList.h"
#include "../../basics/idButton.h"
#include "../../basics/dial.h"
#include "../../basics/statusButton.h"
#include "channel.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
using namespace giada::m;
-geChannel::geChannel(int X, int Y, int W, int H, int type, Channel *ch)
+geChannel::geChannel(int X, int Y, int W, int H, int type, Channel* ch)
: Fl_Group(X, Y, W, H, nullptr),
ch (ch),
type (type)
/* -------------------------------------------------------------------------- */
-void geChannel::cb_arm(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_arm(); }
-void geChannel::cb_mute(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_mute(); }
-void geChannel::cb_solo(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_solo(); }
-void geChannel::cb_changeVol(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_changeVol(); }
+void geChannel::cb_arm(Fl_Widget* v, void* p) { ((geChannel*)p)->cb_arm(); }
+void geChannel::cb_mute(Fl_Widget* v, void* p) { ((geChannel*)p)->cb_mute(); }
+void geChannel::cb_solo(Fl_Widget* v, void* p) { ((geChannel*)p)->cb_solo(); }
+void geChannel::cb_changeVol(Fl_Widget* v, void* p) { ((geChannel*)p)->cb_changeVol(); }
#ifdef WITH_VST
-void geChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((geChannel*)p)->__cb_openFxWindow(); }
+void geChannel::cb_openFxWindow(Fl_Widget* v, void* p) { ((geChannel*)p)->cb_openFxWindow(); }
#endif
/* -------------------------------------------------------------------------- */
-void geChannel::__cb_arm()
+void geChannel::cb_arm()
{
glue_toggleArm(ch, true);
}
/* -------------------------------------------------------------------------- */
-void geChannel::__cb_mute()
+void geChannel::cb_mute()
{
- glue_setMute(ch);
+ glue_toggleMute(ch);
}
/* -------------------------------------------------------------------------- */
-void geChannel::__cb_solo()
+void geChannel::cb_solo()
{
solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch);
}
/* -------------------------------------------------------------------------- */
-void geChannel::__cb_changeVol()
+void geChannel::cb_changeVol()
{
glue_setVolume(ch, vol->value());
}
#ifdef WITH_VST
-void geChannel::__cb_openFxWindow()
+void geChannel::cb_openFxWindow()
{
gu_openSubWindow(G_MainWin, new gdPluginList(pluginHost::CHANNEL, ch), WID_FX_LIST);
}
int geChannel::getColumnIndex()
{
- return ((geColumn*)parent())->getIndex();
+ return static_cast<geColumn*>(parent())->getIndex();
}
static const int MIN_ELEM_W = 20;
- static void cb_arm (Fl_Widget* v, void* p);
- static void cb_mute (Fl_Widget* v, void* p);
- static void cb_solo (Fl_Widget* v, void* p);
- static void cb_changeVol (Fl_Widget* v, void* p);
+ static void cb_arm(Fl_Widget* v, void* p);
+ static void cb_mute(Fl_Widget* v, void* p);
+ static void cb_solo(Fl_Widget* v, void* p);
+ static void cb_changeVol(Fl_Widget* v, void* p);
#ifdef WITH_VST
static void cb_openFxWindow(Fl_Widget* v, void* p);
#endif
-
- inline void __cb_mute();
- inline void __cb_arm();
- inline void __cb_solo();
- inline void __cb_changeVol();
+ void cb_mute();
+ void cb_arm();
+ void cb_solo();
+ void cb_changeVol();
#ifdef WITH_VST
- inline void __cb_openFxWindow();
+ void cb_openFxWindow();
#endif
/* blink
using std::string;
-geChannelButton::geChannelButton(int x, int y, int w, int h, const char *l)
- : geButton(x, y, w, h, l), key("") {}
+geChannelButton::geChannelButton(int x, int y, int w, int h, const char* l)
+ : geButton(x, y, w, h, l),
+ m_key ("")
+{
+}
/* -------------------------------------------------------------------------- */
-void geChannelButton::setKey(const string &k)
+void geChannelButton::setKey(const string& k)
{
- key = k;
+ m_key = k;
}
void geChannelButton::setKey(int k)
{
- if (k == 0)
- key = "";
- else {
- // FIXME - this crap won't work with unicode/utf-8
- char c = (char) k;
- key = c;
- }
+ if (k == 0)
+ m_key = "";
+ else {
+ // FIXME - this crap won't work with unicode/utf-8
+ char c = (char) k;
+ m_key = c;
+ }
}
void geChannelButton::draw()
{
- geButton::draw();
+ geButton::draw();
- if (key == "")
- return;
+ if (m_key == "")
+ return;
- /* draw background */
+ /* draw background */
- fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
+ fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
- /* draw key */
+ /* draw m_key */
- fl_color(G_COLOR_LIGHT_2);
- fl_font(FL_HELVETICA, 11);
- fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
+ fl_color(G_COLOR_LIGHT_2);
+ fl_font(FL_HELVETICA, 11);
+ fl_draw(m_key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
}
void geChannelButton::setInputRecordMode()
{
- bgColor0 = G_COLOR_RED;
+ bgColor0 = G_COLOR_RED;
}
void geChannelButton::setActionRecordMode()
{
- bgColor0 = G_COLOR_BLUE;
- txtColor = G_COLOR_LIGHT_2;
+ bgColor0 = G_COLOR_BLUE;
+ txtColor = G_COLOR_LIGHT_2;
}
/* -------------------------------------------------------------------------- */
-void geChannelButton::setDefaultMode(const char *l)
+void geChannelButton::setDefaultMode(const char* l)
{
- bgColor0 = G_COLOR_GREY_2;
+ bgColor0 = G_COLOR_GREY_2;
bdColor = G_COLOR_GREY_4;
txtColor = G_COLOR_LIGHT_2;
- if (l)
- label(l);
+ if (l)
+ label(l);
}
void geChannelButton::setPlayMode()
{
- bgColor0 = G_COLOR_LIGHT_1;
- bdColor = G_COLOR_LIGHT_1;
- txtColor = G_COLOR_GREY_1;
+ bgColor0 = G_COLOR_LIGHT_1;
+ bdColor = G_COLOR_LIGHT_1;
+ txtColor = G_COLOR_GREY_1;
}
void geChannelButton::setEndingMode()
{
- bgColor0 = G_COLOR_GREY_4;
+ bgColor0 = G_COLOR_GREY_4;
}
{
private:
- std::string key;
+ std::string m_key;
public:
- geChannelButton(int x, int y, int w, int h, const char *l=0);
+ geChannelButton(int x, int y, int w, int h, const char* l=0);
virtual int handle(int e) = 0;
void draw() override;
- void setKey(const std::string &k);
+ void setKey(const std::string& k);
void setKey(int k);
void setPlayMode();
void setEndingMode();
- void setDefaultMode(const char *l=0);
+ void setDefaultMode(const char* l=0);
void setInputRecordMode();
void setActionRecordMode();
};
fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2); // status empty
- if (mixer::recording && ch->armed)
+ if (mixer::recording && ch->isArmed())
fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_RED); // take in progress
else
if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording))
#include "../../../../core/graphics.h"
#include "../../../../core/midiChannel.h"
#include "../../../../utils/gui.h"
+#include "../../../../utils/string.h"
#include "../../../../glue/channel.h"
#include "../../../../glue/io.h"
#include "../../../../glue/recorder.h"
#include "../../../dialogs/gd_mainWindow.h"
-#include "../../../dialogs/sampleEditor.h"
+#include "../../../dialogs/channelNameInput.h"
#include "../../../dialogs/gd_actionEditor.h"
#include "../../../dialogs/gd_warnings.h"
#include "../../../dialogs/gd_keyGrabber.h"
-#include "../../../dialogs/gd_pluginList.h"
+#include "../../../dialogs/pluginList.h"
#include "../../../dialogs/midiIO/midiInputChannel.h"
#include "../../../dialogs/midiIO/midiOutputMidiCh.h"
#include "../../basics/boxtypes.h"
#include "../../basics/statusButton.h"
#include "../../basics/dial.h"
#include "column.h"
+#include "midiChannelButton.h"
#include "midiChannel.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
+using std::string;
using namespace giada::m;
RESIZE_H3,
RESIZE_H4,
__END_RESIZE_SUBMENU__,
+ RENAME_CHANNEL,
CLONE_CHANNEL,
DELETE_CHANNEL
};
/* -------------------------------------------------------------------------- */
-void menuCallback(Fl_Widget *w, void *v)
+void menuCallback(Fl_Widget* w, void* v)
{
- geMidiChannel *gch = static_cast<geMidiChannel*>(w);
+ geMidiChannel* gch = static_cast<geMidiChannel*>(w);
Menu selectedItem = (Menu) (intptr_t) v;
switch (selectedItem)
break;
case Menu::CLONE_CHANNEL:
glue_cloneChannel(gch->ch);
+ break;
+ case Menu::RENAME_CHANNEL:
+ gu_openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
break;
case Menu::DELETE_CHANNEL:
glue_deleteChannel(gch->ch);
/* -------------------------------------------------------------------------- */
-geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel *ch)
+geMidiChannel::geMidiChannel(int X, int Y, int W, int H, MidiChannel* ch)
: geChannel(X, Y, W, H, CHANNEL_MIDI, ch)
{
begin();
/* -------------------------------------------------------------------------- */
-void geMidiChannel::cb_button (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_button(); }
-void geMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geMidiChannel*)p)->__cb_openMenu(); }
+void geMidiChannel::cb_button (Fl_Widget* v, void* p) { ((geMidiChannel*)p)->cb_button(); }
+void geMidiChannel::cb_openMenu(Fl_Widget* v, void* p) { ((geMidiChannel*)p)->cb_openMenu(); }
/* -------------------------------------------------------------------------- */
-void geMidiChannel::__cb_button()
+void geMidiChannel::cb_button()
{
if (button->value())
glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift());
/* -------------------------------------------------------------------------- */
-void geMidiChannel::__cb_openMenu()
+void geMidiChannel::cb_openMenu()
{
Fl_Menu_Item rclick_menu[] = {
{"Edit actions...", 0, menuCallback, (void*) Menu::EDIT_ACTIONS},
{"Large", 0, menuCallback, (void*) Menu::RESIZE_H3},
{"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
{0},
+ {"Rename channel", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
{"Clone channel", 0, menuCallback, (void*) Menu::CLONE_CHANNEL},
{"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
{0}
if (!ch->hasActions)
rclick_menu[(int)Menu::CLEAR_ACTIONS].deactivate();
- Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
+ Fl_Menu_Button* b = new Fl_Menu_Button(0, 0, 100, 50);
b->box(G_CUSTOM_BORDER_BOX);
b->textsize(G_GUI_FONT_SIZE_BASE);
b->textcolor(G_COLOR_LIGHT_2);
b->color(G_COLOR_GREY_2);
- const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
+ const Fl_Menu_Item* m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
if (m)
m->do_callback(this, m->user_data());
return;
void geMidiChannel::update()
{
- if (((MidiChannel*) ch)->midiOut) {
- char tmp[32];
- sprintf(tmp, "-- MIDI (channel %d) --", ((MidiChannel*) ch)->midiOutChan+1);
- mainButton->copy_label(tmp);
- }
+ const MidiChannel* mch = static_cast<const MidiChannel*>(ch);
+
+ string label;
+ if (mch->getName().empty())
+ label = "-- MIDI --";
else
- mainButton->label("-- MIDI --");
+ label = mch->getName().c_str();
+
+ if (mch->midiOut)
+ label += " (ch " + gu_toString(mch->midiOutChan + 1) + " out)";
+
+ mainButton->label(label.c_str());
+
+ vol->value(mch->volume);
+ mute->value(mch->mute);
+ solo->value(mch->solo);
- vol->value(ch->volume);
- mute->value(ch->mute);
- solo->value(ch->solo);
+ mainButton->setKey(mch->key);
- mainButton->setKey(ch->key);
+ arm->value(mch->isArmed());
#ifdef WITH_VST
- fx->status = ch->plugins.size() > 0;
+ fx->status = mch->plugins.size() > 0;
fx->redraw();
#endif
}
#endif
packWidgets();
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char *l)
- : geChannelButton(x, y, w, h, l) {}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int geMidiChannelButton::handle(int e)
-{
- // MIDI drag-n-drop does nothing so far.
- return geButton::handle(e);
-}
+}
\ No newline at end of file
{
private:
- static void cb_button (Fl_Widget *v, void *p);
- static void cb_openMenu (Fl_Widget *v, void *p);
-
- inline void __cb_button ();
- inline void __cb_openMenu ();
- inline void __cb_readActions ();
+ static void cb_button(Fl_Widget* v, void* p);
+ static void cb_openMenu(Fl_Widget* v, void* p);
+ void cb_button();
+ void cb_openMenu();
public:
- geMidiChannel(int x, int y, int w, int h, MidiChannel *ch);
+ geMidiChannel(int x, int y, int w, int h, MidiChannel* ch);
void resize(int x, int y, int w, int h) override;
};
-/* -------------------------------------------------------------------------- */
-
-
-class geMidiChannelButton : public geChannelButton
-{
-public:
- geMidiChannelButton(int x, int y, int w, int h, const char *l=0);
- int handle(int e);
-};
-
-
#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "midiChannelButton.h"
+
+
+geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const char* l)
+ : geChannelButton(x, y, w, h, l)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geMidiChannelButton::handle(int e)
+{
+ // Currently MIDI drag-n-drop does nothing.
+ return geButton::handle(e);
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_MIDI_CHANNEL_BUTTON_H
+#define GE_MIDI_CHANNEL_BUTTON_H
+
+
+#include "channelButton.h"
+
+
+class geMidiChannelButton : public geChannelButton
+{
+public:
+ geMidiChannelButton(int x, int y, int w, int h, const char* l=0);
+ int handle(int e);
+};
+
+
+#endif
\ No newline at end of file
#include "../../../dialogs/gd_mainWindow.h"
#include "../../../dialogs/gd_keyGrabber.h"
#include "../../../dialogs/sampleEditor.h"
+#include "../../../dialogs/channelNameInput.h"
#include "../../../dialogs/gd_actionEditor.h"
#include "../../../dialogs/gd_warnings.h"
#include "../../../dialogs/browser/browserSave.h"
RESIZE_H3,
RESIZE_H4,
__END_RESIZE_SUBMENU__,
+ RENAME_CHANNEL,
CLONE_CHANNEL,
FREE_CHANNEL,
DELETE_CHANNEL
glue_cloneChannel(gch->ch);
break;
}
+ case Menu::RENAME_CHANNEL: {
+ gu_openSubWindow(G_MainWin, new gdChannelNameInput(gch->ch), WID_SAMPLE_NAME);
+ break;
+ }
case Menu::FREE_CHANNEL: {
glue_freeChannel(gch->ch);
break;
{"Large", 0, menuCallback, (void*) Menu::RESIZE_H3},
{"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
{0},
+ {"Rename channel", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
{"Clone channel", 0, menuCallback, (void*) Menu::CLONE_CHANNEL},
{"Free channel", 0, menuCallback, (void*) Menu::FREE_CHANNEL},
{"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
rclick_menu[(int) Menu::EXPORT_SAMPLE].deactivate();
rclick_menu[(int) Menu::EDIT_SAMPLE].deactivate();
rclick_menu[(int) Menu::FREE_CHANNEL].deactivate();
+ rclick_menu[(int) Menu::RENAME_CHANNEL].deactivate();
}
if (!ch->hasActions)
rclick_menu[(int) Menu::CLEAR_ACTIONS].deactivate();
+
/* No 'clear start/stop actions' for those channels in loop mode: they cannot
have start/stop actions. */
void geSampleChannel::__cb_readActions()
{
- glue_startStopReadingRecs(static_cast<SampleChannel*>(ch));
+ glue_toggleReadingRecs(static_cast<SampleChannel*>(ch));
}
setColorsByStatus(ch->status, ch->recStatus);
if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
- if (mixer::recording && ch->armed)
+ if (mixer::recording && ch->isArmed())
mainButton->setInputRecordMode();
if (recorder::active) {
if (recorder::canRec(ch, clock::isRunning(), mixer::recording))
void geSampleChannel::update()
{
- /* update sample button's label */
+ const SampleChannel* sch = static_cast<const SampleChannel*>(ch);
- switch (ch->status) {
+ switch (sch->status) {
case STATUS_EMPTY:
mainButton->label("-- no sample --");
break;
mainButton->label("* file not found! *");
break;
default:
- mainButton->label(static_cast<SampleChannel*>(ch)->wave->getName().c_str());
+ if (sch->getName().empty())
+ mainButton->label(sch->wave->getBasename(false).c_str());
+ else
+ mainButton->label(sch->getName().c_str());
break;
}
- /* update channels. If you load a patch with recorded actions, the 'R'
- * button must be shown. Moreover if the actions are active, the 'R'
- * button must be activated accordingly. */
+ /* Update channels. If you load a patch with recorded actions, the 'R' button
+ must be shown. Moreover if the actions are active, the 'R' button must be
+ activated accordingly. */
- if (ch->hasActions)
+ if (sch->hasActions)
showActionButton();
else
hideActionButton();
- /* updates modebox */
-
- modeBox->value(static_cast<SampleChannel*>(ch)->mode);
+ modeBox->value(sch->mode);
modeBox->redraw();
- /* update volumes+mute+solo */
+ vol->value(sch->volume);
+ mute->value(sch->mute);
+ solo->value(sch->solo);
- vol->value(ch->volume);
- mute->value(ch->mute);
- solo->value(ch->solo);
+ mainButton->setKey(sch->key);
- mainButton->setKey(ch->key);
+ arm->value(sch->isArmed());
#ifdef WITH_VST
- fx->status = ch->plugins.size() > 0;
+ fx->status = sch->plugins.size() > 0;
fx->redraw();
#endif
}
#include "sampleChannelButton.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h,
- const char *l)
+ const char* l)
: geChannelButton(x, y, w, h, l)
{
}
break;
}
case FL_PASTE: {
- geSampleChannel *gch = static_cast<geSampleChannel*>(parent());
- SampleChannel *ch = static_cast<SampleChannel*>(gch->ch);
- int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())).c_str());
+ geSampleChannel* gch = static_cast<geSampleChannel*>(parent());
+ SampleChannel* ch = static_cast<SampleChannel*>(gch->ch);
+ int result = glue_loadChannel(ch, gu_trim(gu_stripFileUrl(Fl::event_text())));
if (result != G_RES_OK)
G_MainWin->keyboard->printChannelMessage(result);
ret = 1;
{
public:
- geSampleChannelButton(int x, int y, int w, int h, const char *l=0);
+ geSampleChannelButton(int x, int y, int w, int h, const char* l=0);
int handle(int e);
};
#include "../../elems/basics/statusButton.h"
#include "../../elems/basics/dial.h"
#include "../../dialogs/gd_mainWindow.h"
-#include "../../dialogs/gd_pluginList.h"
+#include "../../dialogs/pluginList.h"
#include "mainIO.h"
void geMainMenu::__cb_config()
{
- gu_openSubWindow(G_MainWin, new gdConfig(380, 370), WID_CONFIG);
+ gu_openSubWindow(G_MainWin, new gdConfig(400, 370), WID_CONFIG);
}
#include "../../elems/basics/button.h"
#include "../../elems/basics/choice.h"
#include "../../dialogs/gd_mainWindow.h"
-#include "../../dialogs/gd_bpmInput.h"
-#include "../../dialogs/gd_beatsInput.h"
+#include "../../dialogs/bpmInput.h"
+#include "../../dialogs/beatsInput.h"
#include "mainTimer.h"
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 <FL/fl_draw.H>
+#include "../../../core/plugin.h"
+#include "../../../core/const.h"
+#include "../../../core/pluginHost.h"
+#include "../basics/boxtypes.h"
+#include "pluginBrowser.h"
+
+
+using std::vector;
+using std::string;
+using namespace giada::m;
+
+
+gePluginBrowser::gePluginBrowser(int x, int y, int w, int h)
+ : Fl_Browser(x, y, w, h)
+{
+ box(G_CUSTOM_BORDER_BOX);
+ textsize(G_GUI_FONT_SIZE_BASE);
+ textcolor(G_COLOR_LIGHT_2);
+ selection_color(G_COLOR_GREY_4);
+ color(G_COLOR_GREY_2);
+
+ this->scrollbar.color(G_COLOR_GREY_2);
+ this->scrollbar.selection_color(G_COLOR_GREY_4);
+ this->scrollbar.labelcolor(G_COLOR_LIGHT_1);
+ this->scrollbar.slider(G_CUSTOM_BORDER_BOX);
+
+ this->hscrollbar.color(G_COLOR_GREY_2);
+ this->hscrollbar.selection_color(G_COLOR_GREY_4);
+ this->hscrollbar.labelcolor(G_COLOR_LIGHT_1);
+ this->hscrollbar.slider(G_CUSTOM_BORDER_BOX);
+
+ type(FL_HOLD_BROWSER);
+
+ computeWidths();
+
+ column_widths(widths);
+ column_char('\t'); // tabs as column delimiters
+
+ refresh();
+
+ end();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePluginBrowser::refresh()
+{
+ clear();
+
+ 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) ? "" : "@-";
+ 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) + " ?";
+ 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);
+ w0 = (int) fl_width(pi.name.c_str());
+ w1 = (int) fl_width(pi.manufacturerName.c_str());
+ w3 = (int) fl_width(pi.format.c_str());
+ if (w0 > widths[0]) widths[0] = w0;
+ if (w1 > widths[1]) widths[1] = w1;
+ if (w3 > widths[3]) widths[3] = w3;
+ }
+ widths[0] += 60;
+ widths[1] += 60;
+ widths[2] = fl_width("CATEGORY") + 60;
+ widths[3] += 60;
+ widths[4] = 0;
+}
+
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GE_PLUGIN_BROWSER_H
+#define GE_PLUGIN_BROWSER_H
+
+
+#include <FL/Fl_Browser.H>
+
+
+class gePluginBrowser : public Fl_Browser
+{
+private:
+
+ int widths[5] = {0};
+
+ void computeWidths();
+
+public:
+
+ gePluginBrowser(int x, int y, int w, int h);
+
+ void refresh();
+};
+
+#endif
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "../../../core/plugin.h"
+#include "../../../core/const.h"
+#include "../../../glue/plugin.h"
+#include "../basics/boxtypes.h"
+#include "../basics/box.h"
+#include "../basics/slider.h"
+#include "pluginParameter.h"
+
+
+using std::string;
+using namespace giada::c;
+
+
+gePluginParameter::gePluginParameter(int paramIndex, Plugin* p, int X, int Y,
+ int W, int labelWidth)
+ : Fl_Group (X, Y, W, G_GUI_UNIT),
+ m_paramIndex(paramIndex),
+ m_plugin (p)
+{
+ begin();
+
+ m_label = new geBox(x(), y(), labelWidth, G_GUI_UNIT);
+ m_label->copy_label(m_plugin->getParameterName(m_paramIndex).c_str());
+ m_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+
+ m_slider = new geSlider(m_label->x()+m_label->w()+G_GUI_OUTER_MARGIN, y(),
+ w()-(m_label->x()+m_label->w()+G_GUI_OUTER_MARGIN)-VALUE_WIDTH, G_GUI_UNIT);
+ m_slider->value(m_plugin->getParameter(m_paramIndex));
+ m_slider->callback(cb_setValue, (void*)this);
+
+ m_value = new geBox(m_slider->x()+m_slider->w()+G_GUI_OUTER_MARGIN, y(), VALUE_WIDTH, G_GUI_UNIT);
+ m_value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+ m_value->box(G_CUSTOM_BORDER_BOX);
+
+ end();
+ resizable(m_slider);
+ update(false);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePluginParameter::cb_setValue(Fl_Widget* v, void* p) { ((gePluginParameter*)p)->cb_setValue(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePluginParameter::cb_setValue()
+{
+ plugin::setParameter(m_plugin, m_paramIndex, m_slider->value());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gePluginParameter::update(bool changeSlider)
+{
+ string v = m_plugin->getParameterText(m_paramIndex) + " " +
+ m_plugin->getParameterLabel(m_paramIndex);
+ m_value->copy_label(v.c_str());
+ if (changeSlider)
+ m_slider->value(m_plugin->getParameter(m_paramIndex));
+}
+
+
+#endif // #ifdef WITH_VST
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 GE_PLUGIN_PARAMETER_H
+#define GE_PLUGIN_PARAMETER_H
+
+
+#include <FL/Fl_Group.H>
+
+
+class Plugin;
+class geBox;
+class geSlider;
+
+
+class gePluginParameter : public Fl_Group
+{
+private:
+
+ static const int VALUE_WIDTH = 100;
+
+ int m_paramIndex;
+ Plugin* m_plugin;
+
+ geBox* m_label;
+ geSlider* m_slider;
+ geBox* m_value;
+
+ static void cb_setValue(Fl_Widget* v, void* p);
+ void cb_setValue();
+
+public:
+
+ gePluginParameter(int paramIndex, Plugin* p, int x, int y, int w, int labelWidth);
+
+ void update(bool changeSlider);
+};
+
+
+#endif
+
+#endif // #ifdef WITH_VST
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 <FL/fl_draw.H>
-#include "../../core/plugin.h"
-#include "../../core/const.h"
-#include "../../core/pluginHost.h"
-#include "basics/boxtypes.h"
-#include "pluginBrowser.h"
-
-
-using std::vector;
-using std::string;
-using namespace giada::m;
-
-
-gePluginBrowser::gePluginBrowser(int x, int y, int w, int h)
- : Fl_Browser(x, y, w, h)
-{
- box(G_CUSTOM_BORDER_BOX);
- textsize(G_GUI_FONT_SIZE_BASE);
- textcolor(G_COLOR_LIGHT_2);
- selection_color(G_COLOR_GREY_4);
- color(G_COLOR_GREY_2);
-
- this->scrollbar.color(G_COLOR_GREY_2);
- this->scrollbar.selection_color(G_COLOR_GREY_4);
- this->scrollbar.labelcolor(G_COLOR_LIGHT_1);
- this->scrollbar.slider(G_CUSTOM_BORDER_BOX);
-
- this->hscrollbar.color(G_COLOR_GREY_2);
- this->hscrollbar.selection_color(G_COLOR_GREY_4);
- this->hscrollbar.labelcolor(G_COLOR_LIGHT_1);
- this->hscrollbar.slider(G_CUSTOM_BORDER_BOX);
-
- type(FL_HOLD_BROWSER);
-
- computeWidths();
-
- column_widths(widths);
- column_char('\t'); // tabs as column delimiters
-
- refresh();
-
- end();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePluginBrowser::refresh()
-{
- clear();
-
- 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) ? "" : "@-";
- 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) + " ?";
- 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);
- w0 = (int) fl_width(pi.name.c_str());
- w1 = (int) fl_width(pi.manufacturerName.c_str());
- w3 = (int) fl_width(pi.format.c_str());
- if (w0 > widths[0]) widths[0] = w0;
- if (w1 > widths[1]) widths[1] = w1;
- if (w3 > widths[3]) widths[3] = w3;
- }
- widths[0] += 60;
- widths[1] += 60;
- widths[2] = fl_width("CATEGORY") + 60;
- widths[3] += 60;
- widths[4] = 0;
-}
-
-
-#endif
+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2017 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 GE_PLUGIN_BROWSER_H
-#define GE_PLUGIN_BROWSER_H
-
-
-#include <FL/Fl_Browser.H>
-
-
-class gePluginBrowser : public Fl_Browser
-{
-private:
-
- int widths[5] = {0};
-
- void computeWidths();
-
-public:
-
- gePluginBrowser(int x, int y, int w, int h);
-
- void refresh();
-};
-
-#endif
-
-#endif
geRangeTool::geRangeTool(int x, int y, SampleChannel* ch)
- : Fl_Group(x, y, 300, 20),
- m_ch (ch)
+ : Fl_Group(x, y, 280, G_GUI_UNIT),
+ m_ch (ch)
{
- begin();
- m_label = new geBox (x, y, gu_getStringWidth("Range"), 20, "Range", FL_ALIGN_RIGHT);
- m_begin = new geInput(m_label->x()+m_label->w()+4, y, 70, 20);
- m_end = new geInput(m_begin->x()+m_begin->w()+4, y, 70, 20);
- m_reset = new geButton(m_end->x()+m_end->w()+4, y, 70, 20, "Reset");
- end();
-
- m_begin->type(FL_INT_INPUT);
- m_begin->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
- m_begin->callback(cb_setChanPos, this);
-
- m_end->type(FL_INT_INPUT);
- m_end->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
- m_end->callback(cb_setChanPos, this);
-
- m_reset->callback(cb_resetStartEnd, this);
-
- refresh();
+ begin();
+ m_label = new geBox(x, y, gu_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");
+ end();
+
+ m_begin->type(FL_INT_INPUT);
+ m_begin->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
+ m_begin->callback(cb_setChanPos, this);
+
+ m_end->type(FL_INT_INPUT);
+ m_end->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
+ m_end->callback(cb_setChanPos, this);
+
+ m_reset->callback(cb_resetStartEnd, this);
+
+ refresh();
}
void geRangeTool::refresh()
{
- m_begin->value(gu_toString(m_ch->getBegin()).c_str());
- m_end->value(gu_toString(m_ch->getEnd()).c_str());
+ m_begin->value(gu_toString(m_ch->getBegin()).c_str());
+ m_end->value(gu_toString(m_ch->getEnd()).c_str());
}
void geRangeTool::__cb_setChanPos()
{
- sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
- static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
+ 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);
- static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
+ sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
+ static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform(); // TODO - glue's business!
}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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 "../../../core/const.h"
+#include "../../../core/sampleChannel.h"
+#include "../../../utils/gui.h"
+#include "../../../utils/string.h"
+#include "../../../glue/sampleEditor.h"
+#include "../../dialogs/gd_warnings.h"
+#include "../basics/input.h"
+#include "../basics/box.h"
+#include "../basics/button.h"
+#include "shiftTool.h"
+
+
+using namespace giada::c;
+
+
+geShiftTool::geShiftTool(int x, int y, SampleChannel* ch)
+ : Fl_Group(x, y, 300, G_GUI_UNIT),
+ m_ch (ch)
+{
+ begin();
+ m_label = new geBox(x, y, gu_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_toString(ch->getShift()).c_str());
+ m_shift->callback(cb_setShift, (void*)this);
+
+ m_reset->callback(cb_reset, (void*)this);
+
+ refresh();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geShiftTool::cb_setShift(Fl_Widget* w, void* p) { ((geShiftTool*)p)->cb_setShift(); }
+void geShiftTool::cb_reset(Fl_Widget* w, void* p) { ((geShiftTool*)p)->cb_reset(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geShiftTool::cb_setShift()
+{
+ shift(atoi(m_shift->value()));
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geShiftTool::cb_reset()
+{
+ shift(0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geShiftTool::refresh()
+{
+ m_shift->value(gu_toString(m_ch->getShift()).c_str());
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geShiftTool::shift(int f)
+{
+ if (m_ch->isPlaying())
+ gdAlert("Can't shift sample while playing.");
+ else
+ sampleEditor::shift(m_ch, f);
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2017 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_SHIFT_TOOL_H
+#define GE_SHIFT_TOOL_H
+
+
+#include <FL/Fl_Group.H>
+
+
+class SampleChannel;
+class geInput;
+class geButton;
+class geBox;
+
+
+class geShiftTool : public Fl_Group
+{
+private:
+
+ SampleChannel* m_ch;
+
+ geBox* m_label;
+ geInput* m_shift;
+ geButton* m_reset;
+
+ static void cb_setShift(Fl_Widget* w, void* p);
+ static void cb_reset(Fl_Widget* w, void* p);
+ void cb_setShift();
+ void cb_reset();
+
+ void shift(int f);
+
+public:
+
+ geShiftTool(int x, int y, SampleChannel* ch);
+
+ void refresh();
+};
+
+
+#endif
case FL_KEYDOWN: {
if (Fl::event_key() == ' ')
- static_cast<gdSampleEditor*>(window())->__cb_togglePreview();
+ static_cast<gdSampleEditor*>(window())->cb_togglePreview();
else
if (Fl::event_key() == FL_BackSpace)
sampleEditor::rewindPreview(m_ch);
#include <string>
-bool gu_fileExists(const std::string &path);
-bool gu_dirExists(const std::string &path);
-bool gu_isDir(const std::string &path);
-bool gu_isProject(const std::string &path);
-bool gu_mkdir(const std::string &path);
+bool gu_fileExists(const std::string& path);
+bool gu_dirExists(const std::string& path);
+bool gu_isDir(const std::string& path);
+bool gu_isProject(const std::string& path);
+bool gu_mkdir(const std::string& path);
std::string gu_getCurrentPath();
std::string gu_getHomePath();
-std::string gu_basename(const std::string &s);
-std::string gu_dirname(const std::string &s);
-std::string gu_getExt(const std::string &s);
-std::string gu_stripExt(const std::string &s);
-std::string gu_stripFileUrl(const std::string &s);
+
+/* gu_basename
+/path/to/file.txt -> file.txt */
+
+std::string gu_basename(const std::string& s);
+
+/* gu_dirname
+/path/to/file.txt -> /path/to */
+
+std::string gu_dirname(const std::string& s);
+
+/* gu_getExt
+/path/to/file.txt -> txt */
+
+std::string gu_getExt(const std::string& s);
+
+/* gu_stripExt
+/path/to/file.txt -> /path/to/file */
+
+std::string gu_stripExt(const std::string& s);
+
+std::string gu_stripFileUrl(const std::string& s);
#endif
using std::vector;
-string gu_getRealPath(const string &path)
+string gu_getRealPath(const string& path)
{
string out = "";
/* -------------------------------------------------------------------------- */
-string gu_trim(const string &s)
+string gu_trim(const string& s)
{
std::size_t first = s.find_first_not_of(" \n\t");
std::size_t last = s.find_last_not_of(" \n\t");
/* -------------------------------------------------------------------------- */
-string gu_replace(string in, const string &search, const string &replace)
+string gu_replace(string in, const string& search, const string& replace)
{
size_t pos = 0;
while ((pos = in.find(search, pos)) != string::npos) {
/* -------------------------------------------------------------------------- */
-void gu_split(string in, string sep, vector<string> *v)
+void gu_split(string in, string sep, vector<string>* v)
{
string full = in;
string token = "";
#include <vector>
-std::string gu_getRealPath(const std::string &path);
+std::string gu_getRealPath(const std::string& path);
-std::string gu_replace(std::string in, const std::string &search,
- const std::string &replace);
+std::string gu_replace(std::string in, const std::string& search,
+ const std::string& replace);
-std::string gu_trim(const std::string &s);
+std::string gu_trim(const std::string& s);
std::string gu_toString(int i);
-void gu_split(std::string in, std::string sep, std::vector<std::string> *v);
+void gu_split(std::string in, std::string sep, std::vector<std::string>* v);
#endif
* -------------------------------------------------------------------------- */
-#include <chrono>
-#include <thread>
+#include "../core/const.h"
+#ifndef G_OS_MAC
+ #include <chrono>
+ #include <thread>
+#else
+ #include <unistd.h>
+#endif
#include "time.h"
{
void sleep(int millisecs)
{
+#ifndef G_OS_MAC
std::this_thread::sleep_for(std::chrono::milliseconds(millisecs));
+#else
+ usleep(millisecs * 1000);
+#endif
}
}}}; // giada::u::time::
static const int CHANNELS = 2;
static const int BIT_DEPTH = 32;
- /* 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. */
-
- std::unique_ptr<Wave> wave;
-
- SECTION("test basename")
- {
- wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS,
- SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
-
- REQUIRE(wave->getPath() == "path/to/sample.wav");
- REQUIRE(wave->getBasename() == "sample");
- REQUIRE(wave->getBasename(true) == "sample.wav");
- }
-
- SECTION("test change name")
- {
- wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS,
- SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
- wave->setName("waveform");
-
- REQUIRE(wave->getPath() == "path/to/waveform.wav");
- REQUIRE(wave->getBasename() == "waveform");
- REQUIRE(wave->getBasename(true) == "waveform.wav");
- }
-
- SECTION("test memory cleanup")
- {
- float* data = new float[BUFFER_SIZE];
-
- wave = std::unique_ptr<Wave>(new Wave(data, BUFFER_SIZE, CHANNELS,
- SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
- wave->clear();
-
- REQUIRE(wave->getData() == nullptr);
- REQUIRE(wave->getPath() == "");
- REQUIRE(wave->getSize() == 0);
- }
+ /* 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. */
+
+ std::unique_ptr<Wave> wave;
+
+ SECTION("test basename")
+ {
+ wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS,
+ SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
+
+ REQUIRE(wave->getPath() == "path/to/sample.wav");
+ REQUIRE(wave->getBasename() == "sample");
+ REQUIRE(wave->getBasename(true) == "sample.wav");
+ }
+
+ SECTION("test path")
+ {
+ wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS,
+ SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
+
+ wave->setPath("path/is/now/different.mp3");
+
+ REQUIRE(wave->getPath() == "path/is/now/different.mp3");
+
+ wave->setPath("path/is/now/different.mp3", 5);
+
+ REQUIRE(wave->getPath() == "path/is/now/different-5.mp3");
+ }
+
+ SECTION("test change name")
+ {
+ wave = std::unique_ptr<Wave>(new Wave(nullptr, BUFFER_SIZE, CHANNELS,
+ SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
+
+ REQUIRE(wave->getPath() == "path/to/sample.wav");
+ REQUIRE(wave->getBasename() == "sample");
+ REQUIRE(wave->getBasename(true) == "sample.wav");
+ }
+
+ SECTION("test memory cleanup")
+ {
+ float* data = new float[BUFFER_SIZE];
+
+ wave = std::unique_ptr<Wave>(new Wave(data, BUFFER_SIZE, CHANNELS,
+ SAMPLE_RATE, BIT_DEPTH, "path/to/sample.wav"));
+ wave->clear();
+
+ REQUIRE(wave->getData() == nullptr);
+ REQUIRE(wave->getPath() == "");
+ REQUIRE(wave->getSize() == 0);
+ }
}