--------------------------------------------------------------------------------
+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] 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"
+- Resizable channels
+- Remove calls to malloc/free in Mixer (use new/delete instead)
+- Improved UI management of VST plugins
+- Fix infinite loop for one shot retrig samples with quantizer > 0
+- Fix wrong geChannel count while saving a patch
+- Fix missing greyed-out options in Sample Channel's menu when loading a wrong
+ sample
+- Fix crash while audio recording with BPM set below the default 120
+- Print correct octave numbers in Piano Roll
+
+
0.14.2 --- 2017 . 08 . 14
- [Sample Editor] Audible preview (with optional loop mode)
- [Sample Editor] Frame-precise editing
src/gui/elems/basics/radio.cpp \
src/utils/log.h \
src/utils/log.cpp \
+src/utils/time.h \
+src/utils/time.cpp \
src/utils/math.h \
src/utils/math.cpp \
src/utils/gui.h \
Channel::Channel(int type, int status, int bufferSize)
: bufferSize (bufferSize),
- midiFilter (-1),
- pan (0.5f),
- previewMode (G_PREVIEW_NONE),
- type (type),
- status (status),
- key (0),
- volume (G_DEFAULT_VOL),
- volume_i (1.0f),
- volume_d (0.0f),
- mute_i (false),
- mute_s (false),
- mute (false),
- solo (false),
- hasActions (false),
+ midiFilter (-1),
+ pan (0.5f),
+ previewMode (G_PREVIEW_NONE),
+ type (type),
+ status (status),
+ key (0),
+ volume (G_DEFAULT_VOL),
+ volume_i (1.0f),
+ volume_d (0.0f),
+ mute_i (false),
+ mute_s (false),
+ mute (false),
+ solo (false),
+ hasActions (false),
readActions (false),
- armed (false),
- recStatus (REC_STOPPED),
- vChan (nullptr),
- guiChannel (nullptr),
- midiIn (true),
- midiInKeyPress (0x0),
- midiInKeyRel (0x0),
- midiInKill (0x0),
- midiInArm (0x0),
- midiInVolume (0x0),
- midiInMute (0x0),
- midiInSolo (0x0),
- midiOutL (false),
- midiOutLplaying(0x0),
- midiOutLmute (0x0),
- midiOutLsolo (0x0)
+ armed (false),
+ recStatus (REC_STOPPED),
+ vChan (nullptr),
+ guiChannel (nullptr),
+ midiIn (true),
+ midiInKeyPress (0x0),
+ midiInKeyRel (0x0),
+ midiInKill (0x0),
+ midiInArm (0x0),
+ midiInVolume (0x0),
+ midiInMute (0x0),
+ midiInSolo (0x0),
+ midiOutL (false),
+ midiOutLplaying(0x0),
+ midiOutLmute (0x0),
+ midiOutLsolo (0x0)
{
}
void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
{
- key = src->key;
- volume = src->volume;
- volume_i = src->volume_i;
- volume_d = src->volume_d;
- pan = src->pan;
- mute_i = src->mute_i;
- mute_s = src->mute_s;
- mute = src->mute;
- solo = src->solo;
- hasActions = src->hasActions;
- recStatus = src->recStatus;
- midiIn = src->midiIn;
- midiInKeyPress = src->midiInKeyPress;
- midiInKeyRel = src->midiInKeyRel;
- midiInKill = src->midiInKill;
- midiInArm = src->midiInArm;
- midiInVolume = src->midiInVolume;
- midiInMute = src->midiInMute;
- midiInSolo = src->midiInSolo;
- midiOutL = src->midiOutL;
- midiOutLplaying = src->midiOutLplaying;
- midiOutLmute = src->midiOutLmute;
- midiOutLsolo = src->midiOutLsolo;
-
- /* clone plugins */
+ key = src->key;
+ volume = src->volume;
+ volume_i = src->volume_i;
+ volume_d = src->volume_d;
+ pan = src->pan;
+ mute_i = src->mute_i;
+ mute_s = src->mute_s;
+ mute = src->mute;
+ solo = src->solo;
+ hasActions = src->hasActions;
+ recStatus = src->recStatus;
+ midiIn = src->midiIn;
+ midiInKeyPress = src->midiInKeyPress;
+ midiInKeyRel = src->midiInKeyRel;
+ midiInKill = src->midiInKill;
+ midiInArm = src->midiInArm;
+ midiInVolume = src->midiInVolume;
+ midiInMute = src->midiInMute;
+ midiInSolo = src->midiInSolo;
+ midiOutL = src->midiOutL;
+ midiOutLplaying = src->midiOutLplaying;
+ midiOutLmute = src->midiOutLmute;
+ midiOutLsolo = src->midiOutLsolo;
+
+ /* clone plugins */
#ifdef WITH_VST
- for (unsigned i=0; i<src->plugins.size(); i++)
- pluginHost::clonePlugin(src->plugins.at(i), pluginHost::CHANNEL,
- pluginMutex, this);
+ for (unsigned i=0; i<src->plugins.size(); i++)
+ pluginHost::clonePlugin(src->plugins.at(i), pluginHost::CHANNEL,
+ pluginMutex, this);
#endif
- /* clone actions */
-
- for (unsigned i=0; i<recorder::global.size(); i++) {
- for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
- recorder::action *a = recorder::global.at(i).at(k);
- if (a->chan == src->index) {
- recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
- hasActions = true;
- }
- }
- }
+ /* clone actions */
+
+ for (unsigned i=0; i<recorder::global.size(); i++) {
+ for (unsigned k=0; k<recorder::global.at(i).size(); k++) {
+ recorder::action *a = recorder::global.at(i).at(k);
+ if (a->chan == src->index) {
+ recorder::rec(index, a->type, a->frame, a->iValue, a->fValue);
+ hasActions = true;
+ }
+ }
+ }
}
{
patch::channel_t pch;
pch.type = type;
- pch.key = key;
pch.index = index;
+ pch.size = guiChannel->getSize();
+ pch.key = key;
pch.column = guiChannel->getColumnIndex();
pch.mute = mute;
pch.mute_s = mute_s;
if (action->chan == index) {
patch::action_t pac;
pac.type = action->type;
- pac.frame = action->frame;
- pac.fValue = action->fValue;
- pac.iValue = action->iValue;
+ pac.frame = action->frame;
+ pac.fValue = action->fValue;
+ pac.iValue = action->iValue;
pch.actions.push_back(pac);
}
}
Plugin *pPlugin = pluginHost::getPluginByIndex(i, pluginHost::CHANNEL, this);
patch::plugin_t pp;
pp.path = pPlugin->getUniqueId();
- pp.bypass = pPlugin->isBypassed();
+ pp.bypass = pPlugin->isBypassed();
for (int k=0; k<pPlugin->getNumParameters(); k++)
pp.params.push_back(pPlugin->getParameter(k));
for (unsigned k=0; k<pPlugin->midiInParams.size(); k++)
int Channel::readPatch(const string &path, int i, pthread_mutex_t *pluginMutex,
- int samplerate, int rsmpQuality)
+ int samplerate, int rsmpQuality)
{
int ret = 1;
patch::channel_t *pch = &patch::channels.at(i);
midiIn = pch->midiIn;
midiInKeyPress = pch->midiInKeyPress;
midiInKeyRel = pch->midiInKeyRel;
- midiInKill = pch->midiInKill;
- midiInVolume = pch->midiInVolume;
- midiInMute = pch->midiInMute;
- midiInSolo = pch->midiInSolo;
+ midiInKill = pch->midiInKill;
+ midiInVolume = pch->midiInVolume;
+ midiInMute = pch->midiInMute;
+ midiInSolo = pch->midiInSolo;
midiOutL = pch->midiOutL;
midiOutLplaying = pch->midiOutLplaying;
midiOutLmute = pch->midiOutLmute;
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);
- hasActions = true;
+ 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,
- pluginMutex, this);
- if (plugin == nullptr) {
- ret &= 0;
- continue;
- }
+ 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->midiInParams.clear();
- for (unsigned j=0; j<ppl->midiInParams.size(); j++)
- plugin->midiInParams.push_back(ppl->midiInParams.at(j));
+ plugin->midiInParams.clear();
+ for (unsigned j=0; j<ppl->midiInParams.size(); j++)
+ plugin->midiInParams.push_back(ppl->midiInParams.at(j));
ret &= 1;
}
void Channel::setPan(float v)
{
- if (v > 1.0f)
- pan = 1.0f;
- else
- if (v < 0.0f)
- pan = 0.0f;
- else
- pan = v;
+ if (v > 1.0f)
+ pan = 1.0f;
+ else
+ if (v < 0.0f)
+ pan = 0.0f;
+ else
+ pan = v;
}
float Channel::getPan()
{
- return pan;
+ return pan;
}
float Channel::calcPanning(int ch)
{
- if (pan == 0.5f) // center: nothing to do
- return 1.0;
- if (ch == 0)
- return 1.0 - pan;
- else // channel 1
- return pan;
+ if (pan == 0.5f) // center: nothing to do
+ return 1.0;
+ if (ch == 0)
+ return 1.0 - pan;
+ else // channel 1
+ return pan;
}
juce::MidiBuffer &Channel::getPluginMidiEvents()
{
- return midiBuffer;
+ return midiBuffer;
}
void Channel::clearMidiBuffer()
{
- midiBuffer.clear();
+ midiBuffer.clear();
}
/* -- version --------------------------------------------------------------- */
#define G_APP_NAME "Giada"
-#define G_VERSION_STR "0.14.2"
+#define G_VERSION_STR "0.14.3"
#define G_VERSION_MAJOR 0
#define G_VERSION_MINOR 14
-#define G_VERSION_PATCH 2
+#define G_VERSION_PATCH 3
#define CONF_FILENAME "giada.conf"
#define G_GUI_HEIGHT 510
#define G_GUI_PLUGIN_RATE 0.05 // refresh rate for plugin GUIs
#define G_GUI_FONT_SIZE_BASE 12
+#define G_GUI_INNER_MARGIN 4
+#define G_GUI_OUTER_MARGIN 8
+#define G_GUI_UNIT 20 // base unit for elements
+#define G_GUI_CHANNEL_H_1 G_GUI_UNIT
+#define G_GUI_CHANNEL_H_2 G_GUI_UNIT * 2
+#define G_GUI_CHANNEL_H_3 G_GUI_UNIT * 4
+#define G_GUI_CHANNEL_H_4 G_GUI_UNIT * 6
+
#define G_COLOR_RED fl_rgb_color(28, 32, 80)
#define G_COLOR_BLUE fl_rgb_color(113, 31, 31)
#define G_COLOR_RED_ALERT fl_rgb_color(239, 75, 53)
-#define G_COLOR_LIGHT_2 fl_rgb_color(200, 200, 200)
-#define G_COLOR_LIGHT_1 fl_rgb_color(170, 170, 170)
-#define G_COLOR_GREY_4 fl_rgb_color(78, 78, 78)
-#define G_COLOR_GREY_3 fl_rgb_color(54, 54, 54)
-#define G_COLOR_GREY_2 fl_rgb_color(37, 37, 37)
-#define G_COLOR_GREY_1 fl_rgb_color(25, 25, 25)
-#define G_COLOR_BLACK fl_rgb_color(0, 0, 0)
+#define G_COLOR_LIGHT_2 fl_rgb_color(200, 200, 200)
+#define G_COLOR_LIGHT_1 fl_rgb_color(170, 170, 170)
+#define G_COLOR_GREY_4 fl_rgb_color(78, 78, 78)
+#define G_COLOR_GREY_3 fl_rgb_color(54, 54, 54)
+#define G_COLOR_GREY_2 fl_rgb_color(37, 37, 37)
+#define G_COLOR_GREY_1_5 fl_rgb_color(28, 28, 28)
+#define G_COLOR_GREY_1 fl_rgb_color(25, 25, 25)
+#define G_COLOR_BLACK fl_rgb_color(0, 0, 0)
#define G_MAX_BEATS 32
#define G_MAX_BARS 32
#define G_MAX_QUANTIZE 8
-#define G_MAX_PATCHNAME_LEN 32
#define G_MIN_DB_SCALE 60.0f
#define G_MIN_COLUMN_WIDTH 140
#define G_MAX_BOOST_DB 20.0f
#define G_DEFAULT_MIDI_PORT_IN -1
#define G_DEFAULT_MIDI_PORT_OUT -1
#define G_DEFAULT_SAMPLERATE 44100
-#define G_DEFAULT_BUFSIZE 1024
-#define G_DEFAULT_DELAYCOMP 0
+#define G_DEFAULT_BUFSIZE 1024
+#define G_DEFAULT_DELAYCOMP 0
#define G_DEFAULT_BIT_DEPTH 32 // float
#define G_DEFAULT_AUDIO_CHANS 2 // stereo for internal processing
#define G_DEFAULT_VOL 1.0f
#define PATCH_KEY_CHANNELS "channels"
#define PATCH_KEY_CHANNEL_TYPE "type"
#define PATCH_KEY_CHANNEL_INDEX "index"
+#define PATCH_KEY_CHANNEL_SIZE "size"
#define PATCH_KEY_CHANNEL_COLUMN "column"
#define PATCH_KEY_CHANNEL_MUTE "mute"
#define PATCH_KEY_CHANNEL_MUTE_S "mute_s"
float tock[TICKSIZE] = {
- 0.059033, 0.117240, 0.173807, 0.227943, 0.278890, 0.325936,
- 0.368423, 0.405755, 0.437413, 0.462951, 0.482013, 0.494333,
- 0.499738, 0.498153, 0.489598, 0.474195, 0.452159, 0.423798,
- 0.389509, 0.349771, 0.289883, 0.230617, 0.173194, 0.118739,
- 0.068260, 0.022631, -0.017423, -0.051339, -0.078721, -0.099345,
+ 0.059033, 0.117240, 0.173807, 0.227943, 0.278890, 0.325936,
+ 0.368423, 0.405755, 0.437413, 0.462951, 0.482013, 0.494333,
+ 0.499738, 0.498153, 0.489598, 0.474195, 0.452159, 0.423798,
+ 0.389509, 0.349771, 0.289883, 0.230617, 0.173194, 0.118739,
+ 0.068260, 0.022631, -0.017423, -0.051339, -0.078721, -0.099345,
-0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954,
-0.070862, -0.048844
};
float tick[TICKSIZE] = {
- 0.175860, 0.341914, 0.488904, 0.608633, 0.694426, 0.741500,
- 0.747229, 0.711293, 0.635697, 0.524656, 0.384362, 0.222636,
- 0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
+ 0.175860, 0.341914, 0.488904, 0.608633, 0.694426, 0.741500,
+ 0.747229, 0.711293, 0.635697, 0.524656, 0.384362, 0.222636,
+ 0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653,
-0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160,
-0.201360, -0.067752, 0.052194, 0.151746, 0.226280, 0.273493,
- 0.293425, 0.288307, 0.262252, 0.220811, 0.170435, 0.117887,
- 0.069639, 0.031320
+ 0.293425, 0.288307, 0.262252, 0.220811, 0.170435, 0.117887,
+ 0.069639, 0.031320
};
void lineInRec(float* inBuf, unsigned frame)
{
if (!mh::hasArmedSampleChannels() || !kernelAudio::isInputEnabled() || !recording)
- return;
+ return;
/* Delay comp: wait until waitRec reaches delayComp. WaitRec
* returns to 0 in mixerHandler, as soon as the recording ends */
int index = recorder::global.at(i).at(j)->chan;
Channel *ch = mh::getChannelByIndex(index);
ch->parseAction(recorder::global.at(i).at(j), frame,
- clock::getCurrentFrame(), clock::getQuantize(), clock::isRunning());
+ clock::getCurrentFrame(), clock::getQuantize(), clock::isRunning());
}
break;
}
void doQuantize(unsigned frame)
{
- /* Nothing to do if quantizer disabled or a quanto has not passed yet. */
+ /* Nothing to do if quantizer disabled or a quanto has not passed yet. */
- if (clock::getQuantize() == 0 || !clock::quantoHasPassed())
- return;
+ if (clock::getQuantize() == 0 || !clock::quantoHasPassed())
+ return;
if (rewindWait) {
rewindWait = false;
rewind();
void testLastBeat()
{
- if (clock::isOnBeat())
- if (metronome && !tickPlay)
- tockPlay = true;
+ if (clock::isOnBeat())
+ if (metronome && !tickPlay)
+ tockPlay = true;
}
}; // {anonymous}
/* Allocate virtual input channels. vChanInput has variable size: it depends
on how many frames there are in sequencer. */
- allocVirtualInput(framesInSeq);
+ allocVirtualInput(framesInSeq);
- if (vChanInToOut != nullptr)
- free(vChanInToOut);
- vChanInToOut = (float*) malloc(audioBufferSize * 2 * sizeof(float));
+ if (vChanInToOut != nullptr)
+ delete[] vChanInToOut;
+ vChanInToOut = new (std::nothrow) float[audioBufferSize * 2];
+ if (!vChanInToOut) {
+ gu_log("[Mixer::init] vChanInToOut alloc error!\n");
+ return;
+ }
pthread_mutex_init(&mutex_recs, nullptr);
pthread_mutex_init(&mutex_chans, nullptr);
void allocVirtualInput(int frames)
{
if (vChanInput != nullptr)
- free(vChanInput);
- vChanInput = (float*) malloc(frames * sizeof(float));
+ delete[] vChanInput;
+ vChanInput = new (std::nothrow) float[frames];
if (!vChanInput)
- gu_log("[Mixer] vChanInput realloc error!\n");
+ gu_log("[Mixer::allocVirtualInput] vChanInput realloc error!\n");
+ gu_log("[Mixer::allocVirtualInput] vChanInput ready, %d frames\n", frames);
}
return 0;
#ifdef __linux__
- clock::recvJackSync();
+ clock::recvJackSync();
#endif
float* outBuf = (float*) _outBuf;
void rewind()
{
- clock::rewind();
+ clock::rewind();
if (clock::isRunning())
for (unsigned i=0; i<channels.size(); i++)
channels.at(i)->rewind();
int ret = 1;
for (unsigned i=0; i<list->size(); i++) {
patch::plugin_t *ppl = &list->at(i);
- // TODO use glue_addPlugin()
+ // TODO use glue_addPlugin()
Plugin *plugin = pluginHost::addPlugin(ppl->path.c_str(), type,
&mixer::mutex_plugins, nullptr);
if (plugin != nullptr) {
Channel* addChannel(int type)
{
- Channel* ch;
+ Channel* ch;
int bufferSize = kernelAudio::getRealBufSize() * 2;
if (type == CHANNEL_SAMPLE)
while (true) {
if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
- continue;
+ continue;
mixer::channels.push_back(ch);
pthread_mutex_unlock(&mixer::mutex_chans);
break;
ch->index = getNewChanIndex();
gu_log("[addChannel] channel index=%d added, type=%d, total=%d\n",
- ch->index, ch->type, mixer::channels.size());
+ ch->index, ch->type, mixer::channels.size());
return ch;
}
while (true) {
if (pthread_mutex_trylock(&mixer::mutex_chans) != 0)
- continue;
+ continue;
mixer::channels.erase(mixer::channels.begin() + index);
delete ch;
pthread_mutex_unlock(&mixer::mutex_chans);
/* -------------------------------------------------------------------------- */
-Channel *getChannelByIndex(int index)
+Channel* getChannelByIndex(int index)
{
for (unsigned i=0; i<mixer::channels.size(); i++)
if (mixer::channels.at(i)->index == index)
bool hasLogicalSamples()
{
for (unsigned i=0; i<mixer::channels.size(); i++) {
- if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
- continue;
- SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
- if (ch->wave && ch->wave->isLogical())
- return true;
- }
+ if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
+ continue;
+ SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
+ if (ch->wave && ch->wave->isLogical())
+ return true;
+ }
return false;
}
bool hasEditedSamples()
{
for (unsigned i=0; i<mixer::channels.size(); i++)
- {
+ {
if (mixer::channels.at(i)->type != CHANNEL_SAMPLE)
- continue;
- SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
- if (ch->wave && ch->wave->isEdited())
- return true;
- }
+ continue;
+ SampleChannel *ch = static_cast<SampleChannel*>(mixer::channels.at(i));
+ if (ch->wave && ch->wave->isEdited())
+ return true;
+ }
return false;
}
void stopSequencer()
{
- clock::stop();
+ clock::stop();
for (unsigned i=0; i<mixer::channels.size(); i++)
mixer::channels.at(i)->stopBySeq(conf::chansStopOnSeqHalt);
}
/* -------------------------------------------------------------------------- */
-bool uniqueSolo(Channel *ch)
+bool uniqueSolo(Channel* ch)
{
int solos = 0;
for (unsigned i=0; i<mixer::channels.size(); i++) {
{
mixer::ready = false;
- mixer::outVol = patch::masterVolOut;
- mixer::inVol = patch::masterVolIn;
+ mixer::outVol = patch::masterVolOut;
+ mixer::inVol = patch::masterVolIn;
clock::setBpm(patch::bpm);
clock::setBars(patch::bars);
clock::setBeats(patch::beats);
clock::setQuantize(patch::quantize);
- mixer::metronome = patch::metronome;
+ mixer::metronome = patch::metronome;
#ifdef WITH_VST
bool hasArmedSampleChannels()
{
- for (unsigned i=0; i<mixer::channels.size(); i++) {
- Channel *ch = mixer::channels.at(i);
- if (ch->type == CHANNEL_SAMPLE && ch->armed)
- return true;
- }
- return false;
+ for (unsigned i=0; i<mixer::channels.size(); i++) {
+ Channel *ch = mixer::channels.at(i);
+ if (ch->type == CHANNEL_SAMPLE && ch->armed)
+ return true;
+ }
+ return false;
}
samplerate = samplerate <= 0 ? G_DEFAULT_SAMPLERATE : samplerate;
for (unsigned i=0; i<columns.size(); i++) {
- column_t *col = &columns.at(i);
+ column_t* col = &columns.at(i);
col->index = col->index < 0 ? 0 : col->index;
col->width = col->width < G_MIN_COLUMN_WIDTH ? G_MIN_COLUMN_WIDTH : col->width;
}
for (unsigned i=0; i<channels.size(); i++) {
- channel_t *ch = &channels.at(i);
+ channel_t* ch = &channels.at(i);
+ ch->size = ch->size < G_GUI_CHANNEL_H_1 || ch->size > G_GUI_CHANNEL_H_4 ? G_GUI_CHANNEL_H_1 : ch->size;
ch->volume = ch->volume < 0.0f || ch->volume > 1.0f ? G_DEFAULT_VOL : ch->volume;
ch->pan = ch->pan < 0.0f || ch->pan > 1.0f ? 1.0f : ch->pan;
ch->boost = ch->boost < 1.0f ? G_DEFAULT_BOOST : ch->boost;
- ch->pitch = ch->pitch < 0.1f || ch->pitch > 4.0f ? G_DEFAULT_PITCH : ch->pitch;
+ ch->pitch = ch->pitch < 0.1f || ch->pitch > G_MAX_PITCH ? G_DEFAULT_PITCH : ch->pitch;
}
}
/* setInvalid
Helper function used to return invalid status while reading. */
-int setInvalid(json_t *jRoot)
+int setInvalid(json_t* jRoot)
{
json_decref(jRoot);
return PATCH_INVALID;
/* -------------------------------------------------------------------------- */
-bool readCommons(json_t *jContainer)
+bool readCommons(json_t* jContainer)
{
if (!storager::setString(jContainer, PATCH_KEY_HEADER, header)) return 0;
if (!storager::setString(jContainer, PATCH_KEY_VERSION, version)) return 0;
#ifdef WITH_VST
-bool readPlugins(json_t *jContainer, vector<plugin_t> *container, const char *key)
+bool readPlugins(json_t* jContainer, vector<plugin_t>* container, const char* key)
{
- json_t *jPlugins = json_object_get(jContainer, key);
+ json_t* jPlugins = json_object_get(jContainer, key);
if (!storager::checkArray(jPlugins, key))
return 0;
size_t pluginIndex;
- json_t *jPlugin;
+ json_t* jPlugin;
json_array_foreach(jPlugins, pluginIndex, jPlugin) {
if (!storager::checkObject(jPlugin, "")) // TODO pass pluginIndex as string
/* read plugin params */
- json_t *jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
+ json_t* jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS);
if (!storager::checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0;
size_t paramIndex;
- json_t *jParam;
+ json_t* jParam;
json_array_foreach(jParams, paramIndex, jParam)
plugin.params.push_back(json_real_value(jParam));
/* read midiIn params (midi learning on plugins' parameters) */
- json_t *jMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
+ json_t* jMidiInParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS);
if (!storager::checkArray(jMidiInParams, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS)) return 0;
size_t midiInParamIndex;
- json_t *jMidiInParam;
+ json_t* jMidiInParam;
json_array_foreach(jMidiInParams, midiInParamIndex, jMidiInParam)
plugin.midiInParams.push_back(json_integer_value(jMidiInParam));
/* -------------------------------------------------------------------------- */
-bool readActions(json_t *jContainer, channel_t *channel)
+bool readActions(json_t* jContainer, channel_t* channel)
{
- json_t *jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
+ json_t* jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS);
if (!storager::checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS))
return 0;
size_t actionIndex;
- json_t *jAction;
+ json_t* jAction;
json_array_foreach(jActions, actionIndex, jAction) {
if (!storager::checkObject(jAction, "")) // TODO pass actionIndex as string
/* -------------------------------------------------------------------------- */
-bool readChannels(json_t *jContainer)
+bool readChannels(json_t* jContainer)
{
- json_t *jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
+ json_t* jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS);
if (!storager::checkArray(jChannels, PATCH_KEY_CHANNELS))
return 0;
size_t channelIndex;
- json_t *jChannel;
+ json_t* jChannel;
json_array_foreach(jChannels, channelIndex, jChannel) {
string channelIndexStr = "channel " + gu_toString(channelIndex);
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::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;
/* -------------------------------------------------------------------------- */
-bool readColumns(json_t *jContainer)
+bool readColumns(json_t* jContainer)
{
- json_t *jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
+ json_t* jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS);
if (!storager::checkArray(jColumns, PATCH_KEY_COLUMNS))
return 0;
size_t columnIndex;
- json_t *jColumn;
+ json_t* jColumn;
json_array_foreach(jColumns, columnIndex, jColumn) {
string columnIndexStr = "column " + gu_toString(columnIndex);
#ifdef WITH_VST
-void writePlugins(json_t *jContainer, vector<plugin_t> *plugins, const char *key)
+void writePlugins(json_t* jContainer, vector<plugin_t>* plugins, const char* key)
{
- json_t *jPlugins = json_array();
+ json_t* jPlugins = json_array();
for (unsigned j=0; j<plugins->size(); j++) {
- json_t *jPlugin = json_object();
- plugin_t plugin = plugins->at(j);
+ json_t* jPlugin = json_object();
+ plugin_t plugin = plugins->at(j);
json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH, json_string(plugin.path.c_str()));
json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass));
json_array_append_new(jPlugins, jPlugin);
/* plugin params */
- json_t *jPluginParams = json_array();
+ json_t* jPluginParams = json_array();
for (unsigned z=0; z<plugin.params.size(); z++)
json_array_append_new(jPluginParams, json_real(plugin.params.at(z)));
json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PARAMS, jPluginParams);
/* midiIn params (midi learning on plugins' parameters) */
- json_t *jPluginMidiInParams = json_array();
+ json_t* jPluginMidiInParams = json_array();
for (unsigned z=0; z<plugin.midiInParams.size(); z++)
json_array_append_new(jPluginMidiInParams, json_integer(plugin.midiInParams.at(z)));
json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_MIDI_IN_PARAMS, jPluginMidiInParams);
/* -------------------------------------------------------------------------- */
-void writeColumns(json_t *jContainer, vector<column_t> *columns)
+void writeColumns(json_t* jContainer, vector<column_t>* columns)
{
- json_t *jColumns = json_array();
+ json_t* jColumns = json_array();
for (unsigned i=0; i<columns->size(); i++) {
- json_t *jColumn = json_object();
- column_t column = columns->at(i);
+ json_t* jColumn = json_object();
+ column_t column = columns->at(i);
json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index));
json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width));
json_array_append_new(jColumns, jColumn);
/* -------------------------------------------------------------------------- */
-void writeActions(json_t *jContainer, vector<action_t> *actions)
+void writeActions(json_t*jContainer, vector<action_t>*actions)
{
- json_t *jActions = json_array();
+ json_t* jActions = json_array();
for (unsigned k=0; k<actions->size(); k++) {
- json_t *jAction = json_object();
- action_t action = actions->at(k);
+ json_t* jAction = json_object();
+ action_t action = actions->at(k);
json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE, json_integer(action.type));
json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME, json_integer(action.frame));
json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue));
/* -------------------------------------------------------------------------- */
-void writeCommons(json_t *jContainer)
+void writeCommons(json_t* jContainer)
{
json_object_set_new(jContainer, PATCH_KEY_HEADER, json_string(header.c_str()));
json_object_set_new(jContainer, PATCH_KEY_VERSION, json_string(version.c_str()));
/* -------------------------------------------------------------------------- */
-void writeChannels(json_t *jContainer, vector<channel_t> *channels)
+void writeChannels(json_t* jContainer, vector<channel_t>* channels)
{
- json_t *jChannels = json_array();
+ json_t* jChannels = json_array();
for (unsigned i=0; i<channels->size(); i++) {
- json_t *jChannel = json_object();
- channel_t channel = channels->at(i);
+ json_t* jChannel = json_object();
+ channel_t channel = channels->at(i);
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_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));
/* -------------------------------------------------------------------------- */
-int write(const string &file)
+int write(const string& file)
{
- json_t *jRoot = json_object();
+ json_t* jRoot = json_object();
writeCommons(jRoot);
writeColumns(jRoot, &columns);
#endif
if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) {
- gu_log("[write] unable to write patch file!\n");
+ gu_log("[patch::write] unable to write patch file!\n");
return 0;
}
return 1;
/* -------------------------------------------------------------------------- */
-int read(const string &file)
+int read(const string& file)
{
json_error_t jError;
- json_t *jRoot = json_load_file(file.c_str(), 0, &jError);
+ json_t* jRoot = json_load_file(file.c_str(), 0, &jError);
if (!jRoot) {
- gu_log("[read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text);
+ gu_log("[patch::read] unable to read patch file! Error on line %d: %s\n",
+ jError.line, jError.text);
return PATCH_UNREADABLE;
}
{
struct action_t
{
- int type;
- int frame;
- float fValue;
- uint32_t iValue;
+ int type;
+ int frame;
+ float fValue;
+ uint32_t iValue;
};
#ifdef WITH_VST
struct plugin_t
{
- std::string path;
- bool bypass;
- std::vector<float> params;
- std::vector<uint32_t> midiInParams;
+ std::string path;
+ bool bypass;
+ std::vector<float> params;
+ std::vector<uint32_t> midiInParams;
};
#endif
struct channel_t
{
- int type;
- int index;
- int column;
- int mute;
- int mute_s;
- int solo;
- float volume;
- float pan;
- bool midiIn;
- uint32_t midiInKeyPress;
- uint32_t midiInKeyRel;
- uint32_t midiInKill;
- uint32_t midiInArm;
- uint32_t midiInVolume;
- uint32_t midiInMute;
- uint32_t midiInSolo;
- bool midiOutL;
- uint32_t midiOutLplaying;
- uint32_t midiOutLmute;
- uint32_t midiOutLsolo;
- // sample channel
- std::string samplePath;
- int key;
- int mode;
- int begin;
- int end;
- float boost;
- int recActive;
- float pitch;
- bool inputMonitor;
- uint32_t midiInReadActions;
- uint32_t midiInPitch;
- // midi channel
- uint32_t midiOut;
- uint32_t midiOutChan;
-
- std::vector<action_t> actions;
+ int type;
+ int index;
+ int size;
+ int column;
+ int mute;
+ int mute_s;
+ int solo;
+ float volume;
+ float pan;
+ bool midiIn;
+ uint32_t midiInKeyPress;
+ uint32_t midiInKeyRel;
+ uint32_t midiInKill;
+ uint32_t midiInArm;
+ uint32_t midiInVolume;
+ uint32_t midiInMute;
+ uint32_t midiInSolo;
+ bool midiOutL;
+ uint32_t midiOutLplaying;
+ uint32_t midiOutLmute;
+ uint32_t midiOutLsolo;
+ // sample channel
+ std::string samplePath;
+ int key;
+ int mode;
+ int begin;
+ int end;
+ float boost;
+ int recActive;
+ float pitch;
+ bool inputMonitor;
+ uint32_t midiInReadActions;
+ uint32_t midiInPitch;
+ // midi channel
+ uint32_t midiOut;
+ uint32_t midiOutChan;
+
+ std::vector<action_t> actions;
#ifdef WITH_VST
- std::vector<plugin_t> plugins;
+ std::vector<plugin_t> plugins;
#endif
};
struct column_t
{
- int index;
- int width;
- std::vector<int> channels;
+ int index;
+ int width;
+ std::vector<int> channels;
};
extern std::string header;
/* read/write
* Read/write patch to/from file. */
-int write(const std::string &file);
-int read (const std::string &file);
+int write(const std::string& file);
+int read (const std::string& file);
}}}; // giada::m::patch::
#endif
#ifdef WITH_VST
+#include <FL/Fl.H>
#include "../utils/log.h"
+#include "../utils/time.h"
+#include "const.h"
#include "plugin.h"
using std::string;
+using namespace giada::u;
int Plugin::idGenerator = 1;
id (idGenerator++),
bypass(false)
{
- /* Fill midiInParams. All values are empty (0x0): they will be filled during
+ /* 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);
-
- /* Try to enable editor (i.e. plugin's UI) */
- ui = plugin->createEditorIfNeeded();
- if (ui == nullptr)
- gu_log("[Plugin] unable to create editor, the plugin might be GUI-less!\n");
-
plugin->prepareToPlay(samplerate, buffersize);
- gu_log("[Plugin] editor initialized and ready\n");
+ gu_log("[Plugin] plugin initialized and ready\n");
}
Plugin::~Plugin()
{
+ closeEditor();
plugin->suspendProcessing(true);
plugin->releaseResources();
}
/* -------------------------------------------------------------------------- */
-void Plugin::showEditor(void *parent)
+void Plugin::showEditor(void* parent)
{
+ ui = plugin->createEditorIfNeeded();
if (ui == nullptr) {
- gu_log("[Plugin::showEditor] can't show editor!\n");
+ 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. */
+
+#ifdef G_OS_LINUX
+ time::sleep(500);
+#endif
+
ui->setOpaque(true);
ui->addToDesktop(0, parent);
}
bool Plugin::isEditorOpen()
{
- return ui->isVisible() && ui->isOnDesktop();
+ return ui != nullptr && ui->isVisible() && ui->isOnDesktop();
}
{
if (ui == nullptr)
return;
- if (ui->isOnDesktop())
- ui->removeFromDesktop();
+ delete ui;
+ ui = nullptr;
}
#endif
if (f >= wave->getSize())
end = (wave->getSize() - 1) * wave->getChannels();
else
- if (f <= begin)
+ if (f * wave->getChannels() <= begin)
end = begin + wave->getChannels();
else
end = f * wave->getChannels();
//fadeoutTracker = tracker; // store old frame number for xfade
tracker = begin;
mute_i = false;
+ qWait = false; // Was in qWait mode? Reset occured, no more qWait now.
if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING))
tracker = fillChan(vChan, tracker, frame);
}
#include <cmath>
+#include <algorithm>
#include "../utils/log.h"
#include "wave.h"
#include "waveFx.h"
for (int j=0; j<w->getChannels(); j++)
frame[j] *= val;
}
-}; // {anonymous}
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
-float normalizeSoft(Wave *w)
+float getPeak(Wave* w, int a, int b)
{
float peak = 0.0f;
float abs = 0.0f;
- for (int i=0; i<w->getSize(); i++) {
+ for (int i=a; i<b; i++) {
float* frame = w->getFrame(i);
for (int j=0; j<w->getChannels(); j++) // Find highest value in any channel
abs = fabs(frame[j]);
if (abs > peak)
peak = abs;
}
+ return peak;
+}
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+float normalizeSoft(Wave* w)
+{
+ float peak = getPeak(w, 0, w->getSize());
/* peak == 0.0f: don't normalize the silence
* peak > 1.0f: don't reduce the amplitude, just leave it alone */
/* -------------------------------------------------------------------------- */
+void normalizeHard(Wave* w, int a, int b)
+{
+ float peak = getPeak(w, a, b);
+ if (peak == 0.0f || peak > 1.0f) // as in ::normalizeSoft
+ return;
+
+ for (int i=a; i<b; i++) {
+ float* frame = w->getFrame(i);
+ for (int j=0; j<w->getChannels(); j++)
+ frame[j] = frame[j] * (1.0f / peak);
+ }
+ w->setEdited(true);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
int monoToStereo(Wave* w)
{
if (w->getChannels() >= G_DEFAULT_AUDIO_CHANS)
}
w->setEdited(true);
-
- return;
}
int newSize = (b - a) * w->getChannels();
float* newData = new (std::nothrow) float[newSize];
if (newData == nullptr) {
- gu_log("[wfx] unable to allocate memory for trimming\n");
+ gu_log("[wfx::trim] unable to allocate memory!\n");
return G_RES_ERR_MEMORY;
}
/* -------------------------------------------------------------------------- */
+int paste(Wave* src, Wave* des, int aFrame)
+{
+ int srcNumSamples = src->getSize() * src->getChannels();
+ int desNumSamples = des->getSize() * des->getChannels();
+ int aSample = aFrame * des->getChannels();
+
+ int newSize = srcNumSamples + desNumSamples;
+ float* newData = new (std::nothrow) float[newSize];
+ if (newData == nullptr) {
+ gu_log("[wfx::paste] unable to allocate memory!\n");
+ return G_RES_ERR_MEMORY;
+ }
+
+ /* |---original data---|///paste data///|---original data---|
+ chunk 1 chunk 2 chunk 3
+ */
+
+ float* chunk1a = des->getData();
+ float* chunk1b = des->getData() + aSample;
+
+ float* chunk2a = src->getData();
+ float* chunk2b = src->getData() + srcNumSamples;
+
+ float* chunk3a = chunk1b;
+ float* chunk3b = des->getData() + desNumSamples;
+
+ std::copy(chunk1a, chunk1b, newData);
+ std::copy(chunk2a, chunk2b, newData + aSample);
+ std::copy(chunk3a, chunk3b, newData + aSample + srcNumSamples);
+
+ des->free();
+ des->setData(newData, newSize);
+ des->setEdited(true);
+
+ return G_RES_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
void fade(Wave* w, int a, int b, int type)
{
gu_log("[wfx::fade] fade from %d to %d (range = %d)\n", a, b, b-a);
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()));
+
+ std::reverse(begin, end);
+
+ w->setEdited(true);
+}
+
}}}; // giada::m::wfx::
\ No newline at end of file
float normalizeSoft(Wave* w);
+/* normalizeHard
+Normalizes the wave in range a-b by altering values in memory. */
+
+void normalizeHard(Wave* w, int a, int b);
+
int monoToStereo(Wave* w);
void silence(Wave* w, int a, int b);
int cut(Wave* w, int a, int b);
int trim(Wave* w, int a, int b);
+int paste(Wave* src, Wave* dest, int a);
/* fade
- * fade in or fade out selection. Fade In = type 0, Fade Out = type 1 */
+Fades in or fades out selection. Fade In = type 0, Fade Out = type 1 */
void fade(Wave* w, int a, int b, int type);
/* smooth
- * smooth edges of selection. */
+Smooth edges of selection. */
void smooth(Wave* w, int a, int b);
+
+/* reverse
+Flips Wave's data. */
+
+void reverse(Wave* w, int a, int b);
+
}}}; // giada::m::wfx::
#endif
if (header.format & SF_FORMAT_PCM_S8)
return 8;
else if (header.format & SF_FORMAT_PCM_16)
- return 16;
+ return 16;
else if (header.format & SF_FORMAT_PCM_24)
- return 24;
+ return 24;
else if (header.format & SF_FORMAT_PCM_32)
- return 32;
+ return 32;
else if (header.format & SF_FORMAT_PCM_U8)
- return 8;
+ return 8;
else if (header.format & SF_FORMAT_FLOAT)
return 32;
else if (header.format & SF_FORMAT_DOUBLE)
frame1 = [leftChannel, rightChannel]
frame2 = [leftChannel, rightChannel]
... */
-
+
int size = header.frames * header.channels;
float* data = new (std::nothrow) float[size];
if (data == nullptr) {
sf_close(fileIn);
- Wave* wave = new Wave(data, size, header.channels, header.samplerate,
+ Wave* wave = new Wave(data, size, header.channels, header.samplerate,
getBits(header), path);
if (header.channels == 1 && !wfx::monoToStereo(wave)) {
return G_RES_ERR_MEMORY;
}
- Wave *wave = new Wave(data, size, 2, samplerate, G_DEFAULT_BIT_DEPTH, "");
- wave->setLogical(true);
+ 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());
/* -------------------------------------------------------------------------- */
+int createFromWave(const Wave* src, int a, int b, Wave** out)
+{
+ int numChans = src->getChannels();
+ int size = (b - a) * numChans;
+ float* data = new (std::nothrow) float[size];
+ if (data == nullptr) {
+ gu_log("[waveManager::createFromWave] unable to allocate memory\n");
+ return G_RES_ERR_MEMORY;
+ }
+
+ std::copy(src->getData() + (a*numChans), src->getData() + (b*numChans), data);
+
+ Wave* wave = new Wave(data, size, numChans, src->getRate(),
+ src->getBits(), src->getPath());
+ wave->setLogical(true);
+ wave->setName(src->getName() + " part");
+
+ *out = wave;
+
+ gu_log("[waveManager::createFromWave] new Wave created, %d frames\n", size);
+
+ return G_RES_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
int resample(Wave* w, int quality, int samplerate)
{
float ratio = samplerate / (float) w->getRate();
src_data.output_frames = newSizeFrames;
src_data.src_ratio = ratio;
- gu_log("[waveManager::resample] resampling: new size=%d (%d frames)\n",
+ gu_log("[waveManager::resample] resampling: new size=%d (%d frames)\n",
newSizeSamples, newSizeFrames);
int ret = src_simple(&src_data, quality, w->getChannels());
SNDFILE* file = sf_open(path.c_str(), SFM_WRITE, &header);
if (file == nullptr) {
- gu_log("[waveManager::save] unable to open %s for exporting: %s\n",
+ gu_log("[waveManager::save] unable to open %s for exporting: %s\n",
path.c_str(), sf_strerror(file));
return G_RES_ERR_IO;
}
w->setLogical(false);
w->setEdited(false);
-
+
return G_RES_OK;
}
}}}; // giada::m::waveManager
(stereo). */
int createEmpty(int size, int samplerate, const std::string& name, Wave** out);
+
+/* createFromWave
+Creates a new Wave from an existing one, copying the data in range a - b. */
+
+int createFromWave(const Wave* src, int a, int b, Wave** out);
+
int resample(Wave* w, int quality, int samplerate);
int save(Wave* w, const std::string& path);
int glue_loadChannel(SampleChannel* ch, const string& fname)
{
- /* Always stop a channel before loading a new sample in it. This will prevent
- issues if tracker is outside the boundaries of the new sample -> segfault. */
+ /* Always stop a channel before loading a new sample in it. This will prevent
+ issues if tracker is outside the boundaries of the new sample -> segfault. */
- ch->hardStop(0);
+ if (ch->status & (STATUS_PLAY | STATUS_ENDING))
+ ch->hardStop(0);
- /* save the patch and take the last browser's dir in order to re-use it
- * the next time */
+ /* Save the patch and take the last browser's dir in order to re-use it the
+ next time. */
conf::samplePath = gu_dirname(fname);
/* -------------------------------------------------------------------------- */
-Channel* glue_addChannel(int column, int type)
+Channel* glue_addChannel(int column, int type, int size)
{
Channel* ch = mh::addChannel(type);
- geChannel* gch = G_MainWin->keyboard->addChannel(column, ch);
+ geChannel* gch = G_MainWin->keyboard->addChannel(column, ch, size);
ch->guiChannel = gch;
return ch;
}
void glue_deleteChannel(Channel* ch)
{
- if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
- return;
- recorder::clearChan(ch->index);
- ch->hasActions = false;
+ if (!gdConfirmWin("Warning", "Delete channel: are you sure?"))
+ return;
+ recorder::clearChan(ch->index);
+ ch->hasActions = false;
#ifdef WITH_VST
pluginHost::freeStack(pluginHost::CHANNEL, &mixer::mutex_plugins, ch);
#endif
void glue_freeChannel(Channel *ch)
{
- if (ch->status == STATUS_PLAY) {
- if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
- return;
- }
- else
- if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
- return;
+ if (ch->status == STATUS_PLAY) {
+ if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?"))
+ return;
+ }
+ else
+ if (!gdConfirmWin("Warning", "Free channel: are you sure?"))
+ return;
G_MainWin->keyboard->freeChannel(ch->guiChannel);
recorder::clearChan(ch->index);
- ch->hasActions = false;
+ ch->hasActions = false;
ch->empty();
- /* delete any related subwindow */
- /** TODO - use gu_closeAllSubwindows() */
- G_MainWin->delSubWindow(WID_FILE_BROWSER);
- G_MainWin->delSubWindow(WID_ACTION_EDITOR);
- G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
- G_MainWin->delSubWindow(WID_FX_LIST);
+ /* delete any related subwindow */
+ /** TODO - use gu_closeAllSubwindows() */
+ G_MainWin->delSubWindow(WID_FILE_BROWSER);
+ G_MainWin->delSubWindow(WID_ACTION_EDITOR);
+ G_MainWin->delSubWindow(WID_SAMPLE_EDITOR);
+ G_MainWin->delSubWindow(WID_FX_LIST);
}
void glue_toggleInputMonitor(Channel *ch)
{
- SampleChannel *sch = static_cast<SampleChannel*>(ch);
- sch->inputMonitor = !sch->inputMonitor;
+ SampleChannel *sch = static_cast<SampleChannel*>(ch);
+ sch->inputMonitor = !sch->inputMonitor;
}
int glue_cloneChannel(Channel *src)
{
Channel *ch = mh::addChannel(src->type);
- geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch);
+ geChannel *gch = G_MainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(),
+ ch, src->guiChannel->getSize());
ch->guiChannel = gch;
ch->copy(src, &mixer::mutex_plugins);
/* Changing channel volume? Update wave editor (if it's shown). */
- if (!editor) {
- gdSampleEditor *gdEditor = (gdSampleEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR);
- if (gdEditor) {
- Fl::lock();
- gdEditor->volumeTool->refresh();
- Fl::unlock();
- }
- }
+ if (!editor) {
+ gdSampleEditor *gdEditor = (gdSampleEditor*) gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR);
+ if (gdEditor) {
+ Fl::lock();
+ gdEditor->volumeTool->refresh();
+ Fl::unlock();
+ }
+ }
if (!gui) {
Fl::lock();
/* -------------------------------------------------------------------------- */
-void glue_setPitch(SampleChannel *ch, float val)
+void glue_setPitch(SampleChannel* ch, float val)
{
ch->setPitch(val);
- gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->pitchTool->refresh();
/* -------------------------------------------------------------------------- */
-void glue_setPanning(SampleChannel *ch, float val)
+void glue_setPanning(SampleChannel* ch, float val)
{
ch->setPan(val);
- gdSampleEditor *gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
+ gdSampleEditor* gdEditor = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
if (gdEditor) {
Fl::lock();
gdEditor->panTool->refresh();
if (recorder::active && recorder::canRec(ch, clock::isRunning(), mixer::recording)) {
if (!ch->mute) {
recorder::startOverdub(ch->index, G_ACTION_MUTES, clock::getCurrentFrame(),
- kernelAudio::getRealBufSize());
- ch->readActions = false; // don't read actions while overdubbing
- }
+ kernelAudio::getRealBufSize());
+ ch->readActions = false; // don't read actions while overdubbing
+ }
else
recorder::stopOverdub(clock::getCurrentFrame(), clock::getTotalFrames(),
- &mixer::mutex_recs);
+ &mixer::mutex_recs);
}
ch->mute ? ch->unsetMute(false) : ch->setMute(false);
/* addChannel
* add an empty new channel to the stack. Returns the new channel. */
-Channel *glue_addChannel(int column, int type);
+Channel *glue_addChannel(int column, int type, int size);
/* loadChannel
* fill an existing channel with a wave. */
void glue_setBpm(const char *v1, const char *v2)
{
- /* Never change this stuff while recording audio */
+ /* Never change this stuff while recording audio */
- if (mixer::recording)
- return;
+ if (mixer::recording)
+ return;
char bpmS[6];
float bpmF = atof(v1) + (atof(v2)/10);
float oldBpmF = clock::getBpm();
clock::setBpm(bpmF);
- recorder::updateBpm(oldBpmF, bpmF, clock::getQuanto());
+ recorder::updateBpm(oldBpmF, bpmF, clock::getQuanto());
+ mixer::allocVirtualInput(clock::getTotalFrames());
#ifdef __linux__
- kernelAudio::jackSetBpm(clock::getBpm());
+ kernelAudio::jackSetBpm(clock::getBpm());
#endif
- gu_refreshActionEditor();
- G_MainWin->mainTimer->setBpm(bpmS);
+ gu_refreshActionEditor();
+ G_MainWin->mainTimer->setBpm(bpmS);
gu_log("[glue] Bpm changed to %s (real=%f)\n", bpmS, clock::getBpm());
}
void glue_setBpm(float v)
{
- if (v < G_MIN_BPM || v > G_MAX_BPM)
- v = G_DEFAULT_BPM;
- double fIpart;
- double fPpart = modf(v, &fIpart);
- int iIpart = fIpart;
- int iPpart = ceilf(fPpart);
- glue_setBpm(gu_toString(iIpart).c_str(), gu_toString(iPpart).c_str());
+ if (v < G_MIN_BPM || v > G_MAX_BPM)
+ v = G_DEFAULT_BPM;
+ double fIpart;
+ double fPpart = modf(v, &fIpart);
+ int iIpart = fIpart;
+ int iPpart = ceilf(fPpart);
+ glue_setBpm(gu_toString(iIpart).c_str(), gu_toString(iPpart).c_str());
}
void glue_setBeats(int beats, int bars, bool expand)
{
- /* Never change this stuff while recording audio */
+ /* Never change this stuff while recording audio */
- if (mixer::recording)
- return;
+ if (mixer::recording)
+ return;
/* Temp vars to store old data (they are necessary) */
mixer::allocVirtualInput(clock::getTotalFrames());
/* Update recorded actions, if 'expand' required and an expansion is taking
- place. */
+ place. */
if (expand && clock::getBeats() > oldBeats)
recorder::expand(oldTotalFrames, clock::getTotalFrames());
{
mh::rewindSequencer();
- /* FIXME - potential desync when Quantizer is enabled from this point on.
- Mixer would wait, while the following calls would be made regardless of its
- state. */
+ /* FIXME - potential desync when Quantizer is enabled from this point on.
+ Mixer would wait, while the following calls would be made regardless of its
+ state. */
#ifdef __linux__
- if (notifyJack)
- kernelAudio::jackSetPosition(0);
+ if (notifyJack)
+ kernelAudio::jackSetPosition(0);
#endif
if (conf::midiSync == MIDI_SYNC_CLOCK_M)
if (createColumns)
G_MainWin->keyboard->init();
- gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
+ gu_updateMainWinLabel(G_DEFAULT_PATCH_NAME);
if (resetGui)
gu_updateControls();
#include "../gui/elems/sampleEditor/pitchTool.h"
#include "../gui/elems/sampleEditor/rangeTool.h"
#include "../gui/elems/sampleEditor/waveform.h"
+#include "../gui/elems/mainWindow/keyboard/channel.h"
#include "../core/sampleChannel.h"
#include "../core/waveFx.h"
+#include "../core/wave.h"
+#include "../core/waveManager.h"
#include "../core/const.h"
#include "../utils/gui.h"
+#include "../utils/log.h"
#include "channel.h"
#include "sampleEditor.h"
namespace c {
namespace sampleEditor
{
+namespace
+{
+ /* m_waveBuffer
+ A Wave used during cut/copy/paste operations. */
+
+ Wave* m_waveBuffer = nullptr;
+}; // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+
+
gdSampleEditor* getSampleEditorWindow()
{
gdSampleEditor* se = static_cast<gdSampleEditor*>(gu_getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
/* -------------------------------------------------------------------------- */
-void setBeginEndChannel(SampleChannel* ch, int b, int e)
+void setBeginEnd(SampleChannel* ch, int b, int e)
{
ch->setBegin(b);
ch->setEnd(e);
Fl::lock();
gdEditor->rangeTool->refresh();
Fl::unlock();
+
+ gdEditor->waveTools->waveform->recalcPoints();
+ gdEditor->waveTools->waveform->clearSel();
+ gdEditor->waveTools->waveform->redraw();
}
gdAlert("Unable to cut the sample!");
return;
}
- setBeginEndChannel(ch, ch->getBegin(), ch->getEnd());
+ setBeginEnd(ch, ch->getBegin(), ch->getEnd());
gdSampleEditor* gdEditor = getSampleEditorWindow();
gdEditor->waveTools->waveform->clearSel();
gdEditor->waveTools->waveform->refresh();
/* -------------------------------------------------------------------------- */
+void copy(SampleChannel* ch, int a, int b)
+{
+ if (m_waveBuffer != nullptr)
+ delete m_waveBuffer;
+
+ int result = waveManager::createFromWave(ch->wave, a, b, &m_waveBuffer);
+ if (result != G_RES_OK) {
+ gu_log("[sampleEditor::copy] unable to create wave buffer!\n");
+ return;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void paste(SampleChannel* ch, int a)
+{
+ if (!isWaveBufferFull())
+ return;
+
+ wfx::paste(m_waveBuffer, ch->wave, a);
+
+ /* Shift begin/end points to keep the previous position. */
+
+ int delta = m_waveBuffer->getSize();
+ if (a < ch->getBegin() && a < ch->getEnd())
+ setBeginEnd(ch, ch->getBegin() + delta, ch->getEnd() + delta);
+ else
+ if (a < ch->getEnd())
+ setBeginEnd(ch, ch->getBegin(), ch->getEnd() + delta);
+
+ gdSampleEditor* gdEditor = getSampleEditorWindow();
+ gdEditor->waveTools->waveform->clearSel();
+ gdEditor->waveTools->waveform->refresh();
+ gdEditor->updateInfo();
+}
+
+/* -------------------------------------------------------------------------- */
+
+
void silence(SampleChannel* ch, int a, int b)
{
wfx::silence(ch->wave, a, b);
/* -------------------------------------------------------------------------- */
-void setStartEnd(SampleChannel* ch, int a, int b)
+void reverse(SampleChannel* ch, int a, int b)
{
- setBeginEndChannel(ch, a, b);
+ wfx::reverse(ch->wave, a, b);
gdSampleEditor* gdEditor = getSampleEditorWindow();
- gdEditor->waveTools->waveform->recalcPoints();
- gdEditor->waveTools->waveform->clearSel();
- gdEditor->waveTools->waveform->redraw();
+ gdEditor->waveTools->waveform->refresh();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void normalizeHard(SampleChannel* ch, int a, int b)
+{
+ wfx::normalizeHard(ch->wave, a, b);
+ gdSampleEditor* gdEditor = getSampleEditorWindow();
+ gdEditor->waveTools->waveform->refresh();
}
gdAlert("Unable to trim the sample!");
return;
}
- setBeginEndChannel(ch, ch->getBegin(), ch->getEnd());
+ setBeginEnd(ch, ch->getBegin(), ch->getEnd());
gdSampleEditor* gdEditor = getSampleEditorWindow();
gdEditor->waveTools->waveform->clearSel();
gdEditor->waveTools->waveform->refresh();
else
setPlayHead(ch, 0);
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void toNewChannel(SampleChannel* ch, int a, int b)
+{
+ SampleChannel* newCh = static_cast<SampleChannel*>(glue_addChannel(
+ ch->guiChannel->getColumnIndex(), CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+
+ Wave* wave = nullptr;
+ int result = waveManager::createFromWave(ch->wave, a, b, &wave);
+ if (result != G_RES_OK) {
+ gdAlert("Unable to copy to new channel!");
+ return;
+ }
+
+ newCh->pushWave(wave, true);
+
+ newCh->guiChannel->update();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+bool isWaveBufferFull()
+{
+ return m_waveBuffer != nullptr;
+}
+
}}}; // giada::c::sampleEditor::
{
-/* setBeginEndChannel
+/* setBeginEnd
Sets start/end points in the sample editor. */
-void setBeginEndChannel(SampleChannel* ch, int b, int e);
+void setBeginEnd(SampleChannel* ch, int b, int e);
void cut(SampleChannel* ch, int a, int b);
+void copy(SampleChannel* ch, int a, int b);
+
+/* paste
+Pastes what's defined in m_copyBuffer into channel 'ch' at point 'a'. If
+m_copyBuffer is empty, does nothing. */
+
+void paste(SampleChannel* ch, int a);
+
void trim(SampleChannel* ch, int a, int b);
+void reverse(SampleChannel* ch, int a, int b);
+void normalizeHard(SampleChannel* ch, int a, int b);
void silence(SampleChannel* ch, int a, int b);
void fade(SampleChannel* ch, int a, int b, int type);
void smoothEdges(SampleChannel* ch, int a, int b);
-void setStartEnd(SampleChannel* ch, int a, int b);
+
+bool isWaveBufferFull();
/* setPlayHead
Changes playhead's position. Used in preview. */
void setPreview(SampleChannel* ch, int mode);
void rewindPreview(SampleChannel* ch);
+
+/* toNewChannel
+Copies the selected range into a new sample channel. */
+
+void toNewChannel(SampleChannel* ch, int a, int b);
}}}; // giada::c::sampleEditor::
#endif
patch::beats = clock::getBeats();
patch::quantize = clock::getQuantize();
patch::masterVolIn = mixer::inVol;
- patch::masterVolOut = mixer::outVol;
- patch::metronome = mixer::metronome;
+ patch::masterVolOut = mixer::outVol;
+ patch::metronome = mixer::metronome;
#ifdef WITH_VST
/* -------------------------------------------------------------------------- */
-void glue_loadPatch(void *data)
+void glue_loadPatch(void* data)
{
- gdBrowserLoad *browser = (gdBrowserLoad*) data;
+ gdBrowserLoad* browser = (gdBrowserLoad*) data;
string fullPath = browser->getSelectedItem();
bool isProject = gu_isProject(browser->getSelectedItem());
* by 0.8 / total_channels steps. */
float steps = 0.8 / patch::channels.size();
- for (unsigned i=0; i<patch::columns.size(); i++) {
- patch::column_t *col = &patch::columns.at(i);
- G_MainWin->keyboard->addColumn(col->width);
+
+ 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);
+ 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);
ch->readPatch(basePath, k, &mixer::mutex_plugins, conf::samplerate,
- conf::rsmpQuality);
+ conf::rsmpQuality);
}
browser->setStatusBar(steps);
}
/* -------------------------------------------------------------------------- */
-void glue_loadSample(void *data)
+void glue_loadSample(void* data)
{
- gdBrowserLoad *browser = (gdBrowserLoad*) data;
+ gdBrowserLoad* browser = (gdBrowserLoad*) data;
string fullPath = browser->getSelectedItem();
if (fullPath.empty())
return;
- int res = glue_loadChannel((SampleChannel*) browser->getChannel(), fullPath.c_str());
+ int res = glue_loadChannel(static_cast<SampleChannel*>(browser->getChannel()),
+ fullPath);
if (res == G_RES_OK) {
conf::samplePath = gu_dirname(fullPath);
return;
if (static_cast<SampleChannel*>(browser->getChannel())->save(filePath.c_str())) {
- gu_log("[glue_saveSample] sample saved to %s\n", filePath.c_str());
+ gu_log("[glue_saveSample] sample saved to %s\n", filePath.c_str());
conf::samplePath = gu_dirname(filePath);
browser->do_callback();
}
else {
pr = new geNoteEditor(scroller->x(), upperArea->y()+upperArea->h()+8, this);
scroller->add(pr);
- scroller->add(new geResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8));
+ /* TODO - avoid magic number 30 for minimum height */
+ scroller->add(new geResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 30, 8));
}
end();
inline void __cb_zoomIn();
inline void __cb_zoomOut();
- geChoice *actionType;
+ geChoice *actionType;
geGridTool *gridTool;
geButton *zoomIn;
geButton *zoomOut;
gu_setFavicon(this);
set_non_modal();
- label(ch->wave->getName().c_str());
+ copy_label(ch->wave->getName().c_str());
size_range(720, 480);
if (conf::sampleEditorX)
void gdSampleEditor::__cb_reload()
{
+ /* TODO - move to glue::sampleEditor */
if (!gdConfirmWin("Warning", "Reload sample: are you sure?"))
return;
waveTools->waveform->stretchToWindow();
waveTools->updateWaveform();
- sampleEditor::setBeginEndChannel(ch, 0, ch->wave->getSize());
+ sampleEditor::setBeginEnd(ch, 0, ch->wave->getSize());
redraw();
}
switch (i % KEYS) {
case (int) Notes::G:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
- sprintf(note, "%dG", octave);
+ sprintf(note, "%d G", octave);
break;
case (int) Notes::FS:
- sprintf(note, "%dF#", octave);
+ sprintf(note, "%d F#", octave);
break;
case (int) Notes::F:
- sprintf(note, "%dF", octave);
+ sprintf(note, "%d F", octave);
break;
case (int) Notes::E:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
- sprintf(note, "%dE", octave);
+ sprintf(note, "%d E", octave);
break;
case (int) Notes::DS:
- sprintf(note, "%dD#", octave);
+ sprintf(note, "%d D#", octave);
break;
case (int) Notes::D:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
- sprintf(note, "%dD", octave);
+ sprintf(note, "%d D", octave);
break;
case (int) Notes::CS:
- sprintf(note, "%dC#", octave);
+ sprintf(note, "%d C#", octave);
break;
case (int) Notes::C:
- sprintf(note, "%dC", octave);
+ sprintf(note, "%d C", octave);
+ octave--;
break;
case (int) Notes::B:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
- sprintf(note, "%dB", octave);
+ sprintf(note, "%d B", octave);
break;
case (int) Notes::AS:
- sprintf(note, "%dA#", octave);
+ sprintf(note, "%d A#", octave);
break;
case (int) Notes::A:
fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
- sprintf(note, "%dA", octave);
+ sprintf(note, "%d A", octave);
break;
case (int) Notes::GS:
- sprintf(note, "%dG#", octave);
- octave--;
+ sprintf(note, "%d G#", octave);
break;
}
* Shows a resize cursor when hovered over.
* Assumes:
* - Parent is an Fl_Scroll
- * - All children of Fl_Scroll are vertically arranged
+ * - All children of Fl_Scroll are m_vertically arranged
* - The widget above us has a bottom edge touching our top edge
* ie. (w->y()+w->h() == this->y())
*
* When this widget is dragged:
* - The widget above us (with a common edge) will be /resized/
- * vertically
- * - All children below us will be /moved/ vertically
+ * m_vertically
+ * - All children below us will be /moved/ m_vertically
*
* -----------------------------------------------------------------------------
*
#include <FL/Fl.H>
#include <FL/Fl_Scroll.H>
#include <FL/fl_draw.H>
+#include "../../../core/const.h"
#include "resizerBar.h"
-geResizerBar::geResizerBar(int X,int Y,int W,int H, bool vertical)
- : Fl_Box(X,Y,W,H), vertical(vertical)
+geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type)
+ : Fl_Box (X, Y, W, H),
+ m_type (type),
+ m_minSize(minSize),
+ m_lastPos(0),
+ m_hover (false)
{
- last_y = 0;
- min_h = 30;
- if (vertical) {
- orig_h = H;
+ if (m_type == VERTICAL) {
+ m_origSize = H;
labelsize(H);
}
else {
- orig_h = W;
+ m_origSize = W;
labelsize(W);
}
- align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
+ align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
labelfont(FL_COURIER);
visible_focus(0);
}
/* -------------------------------------------------------------------------- */
-void geResizerBar::HandleDrag(int diff)
+void geResizerBar::handleDrag(int diff)
{
- Fl_Scroll *grp = static_cast<Fl_Scroll*>(parent());
+ Fl_Scroll* grp = static_cast<Fl_Scroll*>(parent());
int top;
int bot;
- if (vertical) {
+ if (m_type == VERTICAL) {
top = y();
bot = y()+h();
}
// Possibly clamp 'diff' if widget would get too small..
for (int t=0; t<grp->children(); t++) {
- Fl_Widget *wd = grp->child(t);
- if (vertical) {
- if ((wd->y()+wd->h()) == top) { // found widget directly above?
- if ((wd->h()+diff) < min_h)
- diff = wd->h() - min_h; // clamp
- wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff); // change height
- break; // done with first pass
+ Fl_Widget* wd = grp->child(t);
+ if (m_type == VERTICAL) {
+ if ((wd->y()+wd->h()) == top) { // found widget directly above?
+ if ((wd->h()+diff) < m_minSize)
+ diff = wd->h() - m_minSize; // clamp
+ wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff); // change height
+ break; // done with first pass
}
}
else {
- if ((wd->x()+wd->w()) == top) { // found widget directly above?
- if ((wd->w()+diff) < min_h)
- diff = wd->w() - min_h; // clamp
- wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h()); // change height
- break; // done with first pass
+ if ((wd->x()+wd->w()) == top) { // found widget directly above?
+ if ((wd->w()+diff) < m_minSize)
+ diff = wd->w() - m_minSize; // clamp
+ wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h()); // change height
+ break; // done with first pass
}
}
}
// Second pass: find widgets below us, move based on clamped diff
for (int t=0; t<grp->children(); t++) {
- Fl_Widget *wd = grp->child(t);
- if (vertical) {
+ Fl_Widget* wd = grp->child(t);
+ if (m_type == VERTICAL) {
if (wd->y() >= bot) // found widget below us?
- wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h()); // change position
+ wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h()); // change position
}
else {
if (wd->x() >= bot)
// Change our position last
- if (vertical)
+ if (m_type == VERTICAL)
resize(x(), y()+diff, w(), h());
else
resize(x()+diff, y(), w(), h());
/* -------------------------------------------------------------------------- */
+void geResizerBar::draw()
+{
+ Fl_Box::draw();
+ fl_rectf(x(), y(), w(), h(), m_hover ? G_COLOR_GREY_2 : G_COLOR_GREY_1);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
int geResizerBar::handle(int e)
{
int ret = 0;
int this_y;
- if (vertical)
+ if (m_type == VERTICAL)
this_y = Fl::event_y_root();
else
this_y = Fl::event_x_root();
break;
case FL_ENTER:
ret = 1;
- fl_cursor(vertical ? FL_CURSOR_NS : FL_CURSOR_WE);
+ fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
+ m_hover = true;
+ redraw();
break;
case FL_LEAVE:
ret = 1;
fl_cursor(FL_CURSOR_DEFAULT);
+ m_hover = false;
+ redraw();
break;
case FL_PUSH:
ret = 1;
- last_y = this_y;
+ m_lastPos = this_y;
break;
case FL_DRAG:
- HandleDrag(this_y-last_y);
- last_y = this_y;
+ handleDrag(this_y-m_lastPos);
+ m_lastPos = this_y;
ret = 1;
break;
default: break;
/* -------------------------------------------------------------------------- */
-void geResizerBar::resize(int X,int Y,int W,int H)
+int geResizerBar::getMinSize() const
+{
+ return m_minSize;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geResizerBar::resize(int x, int y, int w, int h)
{
- if (vertical)
- Fl_Box::resize(X,Y,W,orig_h); // height of resizer stays constant size
- else
- Fl_Box::resize(X,Y,orig_h,H);
+ if (m_type == VERTICAL)
+ Fl_Box::resize(x, y, w, m_origSize); // Height of resizer stays constant size
+ else
+ Fl_Box::resize(x, y, m_origSize, h);
}
{
private:
- /* TODO - use more general variable names
- * (last_y -> last_?, min_h -> min_?, ...) */
+ bool m_type;
+ int m_origSize;
+ int m_minSize;
+ int m_lastPos;
+ bool m_hover;
- bool vertical;
- int orig_h;
- int last_y;
- int min_h; // min height for widget above us
-
- void HandleDrag(int diff);
+ void handleDrag(int diff);
public:
- /* 'vertical' defines the bar movement. Vertical=true: the bar moves
- * vertically (up and down). */
+ static const int HORIZONTAL = 0;
+ static const int VERTICAL = 1;
- geResizerBar(int x, int y, int w, int h, bool vertical=true);
+ geResizerBar(int x, int y, int w, int h, int minSize, bool type=VERTICAL);
- inline void setMinSize(int val) { min_h = val; }
- inline int getMinSize() { return min_h; }
+ int handle(int e) override;
+ void draw() override;
- int handle(int e);
- void resize(int x, int y, int w, int h);
+ int getMinSize() const;
+ void resize(int x, int y, int w, int h);
};
#include "../../../dialogs/gd_pluginList.h"
#include "../../basics/idButton.h"
#include "../../basics/dial.h"
+#include "../../basics/statusButton.h"
#include "column.h"
+#include "channelStatus.h"
#include "channelButton.h"
#include "channel.h"
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)
+ ch (ch),
+ type (type)
{
}
void geChannel::__cb_arm()
{
- glue_toggleArm(ch, true);
+ glue_toggleArm(ch, true);
}
if (gu_getBlinker() > 6)
mainButton->setPlayMode();
else
- mainButton->setDefaultMode();
+ mainButton->setDefaultMode();
}
void geChannel::setColorsByStatus(int playStatus, int recStatus)
{
- switch (playStatus) {
- case STATUS_OFF:
- case STATUS_EMPTY:
- mainButton->setDefaultMode();
- button->imgOn = channelPlay_xpm;
- button->imgOff = channelStop_xpm;
- button->redraw();
- break;
- case STATUS_PLAY:
- mainButton->setPlayMode();
- button->imgOn = channelStop_xpm;
- button->imgOff = channelPlay_xpm;
- button->redraw();
- break;
- case STATUS_WAIT:
- blink();
- break;
- case STATUS_ENDING:
- mainButton->setEndingMode();
- break;
- }
-
- switch (recStatus) {
- case REC_WAITING:
- blink();
- break;
- case REC_ENDING:
- mainButton->setEndingMode();
- break;
- }
+ switch (playStatus) {
+ case STATUS_OFF:
+ case STATUS_EMPTY:
+ mainButton->setDefaultMode();
+ button->imgOn = channelPlay_xpm;
+ button->imgOff = channelStop_xpm;
+ button->redraw();
+ break;
+ case STATUS_PLAY:
+ mainButton->setPlayMode();
+ button->imgOn = channelStop_xpm;
+ button->imgOff = channelPlay_xpm;
+ button->redraw();
+ break;
+ case STATUS_WAIT:
+ blink();
+ break;
+ case STATUS_ENDING:
+ mainButton->setEndingMode();
+ break;
+ }
+
+ switch (recStatus) {
+ case REC_WAITING:
+ blink();
+ break;
+ case REC_ENDING:
+ mainButton->setEndingMode();
+ break;
+ }
}
void geChannel::packWidgets()
{
- /* Count visible widgets and resize mainButton according to how many widgets
- are visible. */
-
- int visibles = 0;
- for (int i=0; i<children(); i++) {
- child(i)->size(20, 20); // also normalize widths
- if (child(i)->visible())
- visibles++;
- }
- mainButton->size(w() - ((visibles - 1) * (24)), 20); // -1: exclude itself
-
- /* Reposition everything else */
-
- for (int i=1, p=0; i<children(); i++) {
- if (!child(i)->visible())
- continue;
- for (int k=i-1; k>=0; k--) // Get the first visible item prior to i
- if (child(k)->visible()) {
- p = k;
- break;
- }
- child(i)->position(child(p)->x() + child(p)->w() + 4, y());
- }
-
- init_sizes(); // Resets the internal array of widget sizes and positions
+ /* Count visible widgets and resize mainButton according to how many widgets
+ are visible. */
+
+ int visibles = 0;
+ for (int i=0; i<children(); i++) {
+ child(i)->size(MIN_ELEM_W, child(i)->h()); // also normalize widths
+ if (child(i)->visible())
+ visibles++;
+ }
+ mainButton->size(w() - ((visibles - 1) * (MIN_ELEM_W + G_GUI_INNER_MARGIN)), // -1: exclude itself
+ mainButton->h());
+
+ /* Reposition everything else */
+
+ for (int i=1, p=0; i<children(); i++) {
+ if (!child(i)->visible())
+ continue;
+ for (int k=i-1; k>=0; k--) // Get the first visible item prior to i
+ if (child(k)->visible()) {
+ p = k;
+ break;
+ }
+ child(i)->position(child(p)->x() + child(p)->w() + G_GUI_INNER_MARGIN, child(i)->y());
+ }
+
+ init_sizes(); // Resets the internal array of widget sizes and positions
}
return ret;
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geChannel::changeSize(int H)
+{
+ size(w(), H);
+
+ int Y = y() + (H / 2 - (G_GUI_UNIT / 2));
+
+ button->resize(x(), Y, w(), G_GUI_UNIT);
+ arm->resize(x(), Y, w(), G_GUI_UNIT);
+ mainButton->resize(x(), y(), w(), H);
+ mute->resize(x(), Y, w(), G_GUI_UNIT);
+ solo->resize(x(), Y, w(), G_GUI_UNIT);
+ vol->resize(x(), Y, w(), G_GUI_UNIT);
+#ifdef WITH_VST
+ fx->resize(x(), Y, w(), G_GUI_UNIT);
+#endif
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geChannel::getSize()
+{
+ return h();
+}
static const int BREAK_ARM = 168;
#endif
- static void cb_arm (Fl_Widget *v, void *p);
- static void cb_mute (Fl_Widget *v, void *p);
- static void cb_solo (Fl_Widget *v, void *p);
- static void cb_changeVol (Fl_Widget *v, void *p);
+ 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);
#ifdef WITH_VST
- static void cb_openFxWindow(Fl_Widget *v, void *p);
+ static void cb_openFxWindow(Fl_Widget* v, void* p);
#endif
inline void __cb_mute();
public:
- geChannel(int x, int y, int w, int h, int type, Channel *ch);
+ geChannel(int x, int y, int w, int h, int type, Channel* ch);
/* reset
* reset channel to initial status. */
virtual void refresh() = 0;
+ /* changeSize
+ Changes channel's size according to a template (x1, x2, ...). */
+
+ virtual void changeSize(int h);
+
/* keypress
* what to do when the corresponding key is pressed. */
int getColumnIndex();
- Channel *ch;
-
- geIdButton *button;
- geChannelStatus *status;
- geButton *arm;
- geChannelButton *mainButton;
- geButton *mute;
- geButton *solo;
- geDial *vol;
+ int getSize();
+
+ Channel* ch;
+
+ geIdButton* button;
+ geChannelStatus* status;
+ geButton* arm;
+ geChannelButton* mainButton;
+ geButton* mute;
+ geButton* solo;
+ geDial* vol;
#ifdef WITH_VST
- geStatusButton *fx;
+ geStatusButton* fx;
#endif
int type;
* -------------------------------------------------------------------------- */
+#include <cassert>
#include <FL/fl_draw.H>
#include <FL/Fl_Menu_Button.H>
#include "../../../../core/sampleChannel.h"
+#include "../../../../core/midiChannel.h"
#include "../../../../glue/channel.h"
#include "../../../../utils/log.h"
#include "../../../../utils/fs.h"
using std::vector;
+using std::string;
-geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard *parent)
- : Fl_Group(X, Y, W, H), parent(parent), index(index)
+geColumn::geColumn(int X, int Y, int W, int H, int index, geKeyboard* parent)
+ : Fl_Group(X, Y, W, H),
+ m_parent(parent),
+ m_index (index)
{
- /* geColumn does a bit of a mess: we pass a pointer to its parent (geKeyboard) and
- the geColumn itself deals with the creation of another widget, outside geColumn
- and inside geKeyboard, which handles the vertical resize bar (geResizerBar).
- The resizer cannot stay inside geColumn: it needs a broader view on the other
- side widgets. The view can be obtained from geKeyboard only (the upper level).
- Unfortunately, parent() can be nullptr: at this point (i.e the constructor)
- geColumn is still detached from any parent. We use a custom geKeyboard *parent
- instead. */
+ /* geColumn does a bit of a mess: we pass a pointer to its m_parent (geKeyboard) and
+ the geColumn itself deals with the creation of another widget, outside geColumn
+ and inside geKeyboard, which handles the vertical resize bar (geResizerBar).
+ The resizer cannot stay inside geColumn: it needs a broader view on the other
+ side widgets. The view can be obtained from geKeyboard only (the upper level).
+ Unfortunately, parent() can be nullptr: at this point (i.e the constructor)
+ geColumn is still detached from any parent. We use a custom geKeyboard *parent
+ instead. */
begin();
- addChannelBtn = new geButton(x(), y(), w(), 20, "Add new channel");
+ m_addChannelBtn = new geButton(x(), y(), w(), G_GUI_UNIT, "Add new channel");
end();
- resizer = new geResizerBar(x()+w(), y(), 16, h(), false);
- resizer->setMinSize(G_MIN_COLUMN_WIDTH);
- parent->add(resizer);
+ m_resizer = new geResizerBar(x()+w(), y(), G_GUI_OUTER_MARGIN * 2, h(),
+ G_MIN_COLUMN_WIDTH, geResizerBar::HORIZONTAL);
+ m_parent->add(m_resizer);
- addChannelBtn->callback(cb_addChannel, (void*)this);
+ m_addChannelBtn->callback(cb_addChannel, (void*)this);
}
geColumn::~geColumn()
{
- /* FIXME - this could actually cause a memory leak. resizer is
- just removed, not deleted. But we cannot delete it right now. */
+ /* FIXME - this could actually cause a memory leak. m_resizer is
+ just removed, not deleted. But we cannot delete it right now. */
- parent->remove(resizer);
+ m_parent->remove(m_resizer);
}
return 1;
}
case FL_PASTE: { // handle actual drop (paste) operation
- vector<std::string> paths;
+ vector<string> paths;
gu_split(Fl::event_text(), "\n", &paths);
bool fails = false;
int result = 0;
- for (unsigned i=0; i<paths.size(); i++) {
- gu_log("[geColumn::handle] loading %s...\n", paths.at(i).c_str());
- SampleChannel *c = (SampleChannel*) glue_addChannel(index, CHANNEL_SAMPLE);
- result = glue_loadChannel(c, gu_stripFileUrl(paths.at(i)).c_str());
+ for (string& path : paths) {
+ gu_log("[geColumn::handle] loading %s...\n", path.c_str());
+ SampleChannel* c = static_cast<SampleChannel*>(glue_addChannel(
+ m_index, CHANNEL_SAMPLE, G_GUI_CHANNEL_H_1));
+ result = glue_loadChannel(c, gu_stripFileUrl(path));
if (result != G_RES_OK) {
deleteChannel(c->guiChannel);
fails = true;
if (paths.size() > 1)
gdAlert("Some files were not loaded successfully.");
else
- parent->printChannelMessage(result);
+ m_parent->printChannelMessage(result);
}
return 1;
}
void geColumn::resize(int X, int Y, int W, int H)
{
- /* resize all children */
+ /* Resize all children, including "add channel" button. */
- int ch = children();
- for (int i=0; i<ch; i++) {
- Fl_Widget *c = child(i);
- c->resize(X, Y + (i * (c->h() + 4)), W, c->h());
- }
+ for (int i=0; i<children(); i++) {
+ Fl_Widget* wgCurr = child(i);
+ Fl_Widget* wgPrev = i == 0 ? nullptr : child(i - 1);
+ wgCurr->resize(X, (wgPrev == nullptr ? Y : wgPrev->y() + wgPrev->h() + G_GUI_INNER_MARGIN),
+ W, wgCurr->h());
+ }
- /* resize group itself */
+ /* Resize group itself. Must use internal functions, resize() would trigger
+ infinite recursion. */
- x(X); y(Y); w(W); h(H);
+ x(X); y(Y); w(W); h(H);
- /* resize resizerBar */
+ /* Resize resizerBar. */
- resizer->size(16, H);
+ m_resizer->size(G_GUI_OUTER_MARGIN * 2, H);
}
void geColumn::refreshChannels()
{
for (int i=1; i<children(); i++)
- ((geChannel*) child(i))->refresh();
+ static_cast<geChannel*>(child(i))->refresh();
}
void geColumn::draw()
{
- fl_color(fl_rgb_color(27, 27, 27));
+ fl_color(G_COLOR_GREY_1_5);
fl_rectf(x(), y(), w(), h());
- /* call draw and then redraw in order to avoid channel corruption when
- scrolling horizontally */
+ /* call draw and then redraw in order to avoid channel corruption when
+ scrolling horizontally */
- for (int i=0; i<children(); i++) {
- child(i)->draw();
- child(i)->redraw();
- }
+ for (int i=0; i<children(); i++) {
+ child(i)->draw();
+ child(i)->redraw();
+ }
}
/* -------------------------------------------------------------------------- */
-void geColumn::cb_addChannel(Fl_Widget *v, void *p) { ((geColumn*)p)->__cb_addChannel(); }
+void geColumn::cb_addChannel(Fl_Widget* v, void* p) { ((geColumn*)p)->__cb_addChannel(); }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geColumn::repositionChannels()
+{
+ int totalH = 0;
+ for (int i=0; i<children(); i++)
+ totalH += child(i)->h() + G_GUI_INNER_MARGIN;
+ resize(x(), y(), w(), totalH + 66); // evil space for drag n drop
+}
/* -------------------------------------------------------------------------- */
-geChannel *geColumn::addChannel(Channel *ch)
+geChannel* geColumn::addChannel(Channel* ch, int size)
{
- int currentY = y() + children() * 24;
- geChannel *gch = nullptr;
+ geChannel* gch = nullptr;
+
+ /* All geChannels are added with y=0. That's not a problem, they will be
+ repositioned later on during geColumn::resize(). */
+
if (ch->type == CHANNEL_SAMPLE)
- gch = (geSampleChannel*) new geSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch);
+ gch = new geSampleChannel(x(), 0, w(), size, static_cast<SampleChannel*>(ch));
else
- gch = (geMidiChannel*) new geMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch);
+ gch = new geMidiChannel(x(), 0, w(), size, static_cast<MidiChannel*>(ch));
add(gch);
- resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop
- gch->redraw(); // avoid corruption
- parent->redraw(); // redraw Keyboard
+
+ repositionChannels();
+ gch->redraw(); // fix corruption
+ m_parent->redraw(); // redraw Keyboard
return gch;
}
/* -------------------------------------------------------------------------- */
-void geColumn::deleteChannel(geChannel *gch)
+void geColumn::deleteChannel(geChannel* gch)
{
gch->hide();
remove(gch);
delete gch;
- /* reposition all other channels and resize this group */
/** TODO
* reposition is useless when called by geColumn::clear(). Add a new
* parameter to skip the operation */
- for (int i=0; i<children(); i++) {
- gch = (geChannel*) child(i);
- gch->position(gch->x(), y()+(i*24));
- }
- size(w(), children() * 24 + 66); // evil space for drag n drop
- redraw();
+ repositionChannels();
}
void geColumn::__cb_addChannel()
{
- gu_log("[geColumn::__cb_addChannel] index = %d\n", index);
+ gu_log("[geColumn::__cb_addChannel] m_index = %d\n", m_index);
int type = openTypeMenu();
if (type)
- glue_addChannel(index, type);
+ glue_addChannel(m_index, type, G_GUI_CHANNEL_H_1);
}
{0}
};
- 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);
else {
while (children() >= 2) { // skip "add new channel" btn
int i = children()-1;
- deleteChannel((geChannel*)child(i));
+ deleteChannel(static_cast<geChannel*>(child(i)));
}
}
}
/* -------------------------------------------------------------------------- */
-Channel *geColumn::getChannel(int i)
+Channel* geColumn::getChannel(int i)
{
- geChannel *gch = (geChannel*) child(i);
- if (gch->type == CHANNEL_SAMPLE)
- return ((geSampleChannel*) child(i))->ch;
- else
- return ((geMidiChannel*) child(i))->ch;
+ return static_cast<geChannel*>(child(i + 1))->ch; // Skip "add channel"
}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int geColumn::getIndex() { return m_index; }
+void geColumn::setIndex(int i) { m_index = i; }
+bool geColumn::isEmpty() { return children() == 1; }
+int geColumn::countChannels() { return children() - 1; }
\ No newline at end of file
{
private:
- static void cb_addChannel (Fl_Widget *v, void *p);
+ static void cb_addChannel (Fl_Widget* v, void* p);
inline void __cb_addChannel();
int openTypeMenu();
- geButton *addChannelBtn;
- geResizerBar *resizer;
- geKeyboard *parent;
+ geButton* m_addChannelBtn;
+ geResizerBar* m_resizer;
+ geKeyboard* m_parent;
- int index;
+ int m_index;
public:
- geColumn(int x, int y, int w, int h, int index, geKeyboard *parent);
+ geColumn(int x, int y, int w, int h, int index, geKeyboard* parent);
~geColumn();
/* addChannel
- * add a new channel in this column and set the internal pointer
- * to channel to 'ch'. */
+ Adds a new channel in this column and set the internal pointer to channel
+ to 'ch'. */
- geChannel *addChannel(Channel *ch);
+ geChannel* addChannel(Channel* ch, int size);
- /* handle */
+ int handle(int e) override;
+ void draw() override;
+ void resize(int x, int y, int w, int h) override;
- int handle(int e);
-
- /* resize
- * custom resize behavior. */
+ /* clear
+ Removes all channels from the column. If full==true, delete also the "add new
+ channel" button. */
- void resize(int x, int y, int w, int h);
+ void clear(bool full=false);
/* deleteChannel
- * remove the channel 'gch' from this column. */
+ Removes the channel 'gch' from this column. */
- void deleteChannel(geChannel *gch);
+ void deleteChannel(geChannel* gch);
+
+ void repositionChannels();
/* refreshChannels
- * update channels' graphical statues. Called on each GUI cycle. */
+ Updates channels' graphical statues. Called on each GUI cycle. */
void refreshChannels();
- /* getChannel */
-
- Channel *getChannel(int i);
-
- /* clear
- * remove all channels from the column. If full==true, delete also the
- * "add new channel" button. This method ovverrides the inherited one
- * from Fl_Group. */
-
- void clear(bool full=false);
-
- void draw();
-
- inline int getIndex() { return index; }
- inline void setIndex(int i) { index = i; }
- inline bool isEmpty() { return children() == 1; }
- inline int countChannels() { return children(); }
+ Channel* getChannel(int i);
+ int getIndex();
+ void setIndex(int i);
+ bool isEmpty();
+ int countChannels();
};
/* -------------------------------------------------------------------------- */
-geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, bool build)
+geChannel* geKeyboard::addChannel(int colIndex, Channel* ch, int size, bool build)
{
geColumn* col = getColumnByIndex(colIndex);
gu_log("[geKeyboard::addChannel] created new column with index=%d\n", colIndex);
}
- gu_log("[geKeyboard::addChannel] add to column with index = %d\n", col->getIndex());
- return col->addChannel(ch);
+ gu_log("[geKeyboard::addChannel] add to column with index=%d, size=%d\n",
+ col->getIndex(), size);
+ return col->addChannel(ch, size);
}
gdAlert("Unable to read this sample.");
else if (res == G_RES_ERR_PATH_TOO_LONG)
gdAlert("File path too long.");
+ else if (res == G_RES_ERR_NO_DATA)
+ gdAlert("No file specified.");
else
gdAlert("Unknown error.");
}
void init();
/* addChannel
- * add a new channel to geChannels. Used by callbacks and during
- * patch loading. Requires Channel (and not geChannel). If build is
- * set to true, also generate the corresponding column if column (index) does
- * not exist yet. */
+ Adds a new channel to geChannels. Used by callbacks and during patch loading.
+ Requires Channel (and not geChannel). If build is set to true, also generate
+ the corresponding column if column (index) does not exist yet. */
- geChannel* addChannel(int column, Channel* ch, bool build=false);
+ geChannel* addChannel(int column, Channel* ch, int size, bool build=false);
/* addColumn
* add a new column to the top of the stack. */
*
* -----------------------------------------------------------------------------
*
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) G_GUI_UNIT10-G_GUI_UNIT17 Giovanni A. Zuliani | Monocasual
*
* This file is part of Giada - Your Hardcore Loopmachine.
*
#include "../../basics/idButton.h"
#include "../../basics/statusButton.h"
#include "../../basics/dial.h"
+#include "column.h"
#include "midiChannel.h"
{
enum class Menu
{
- EDIT_ACTIONS = 0,
- CLEAR_ACTIONS,
- CLEAR_ACTIONS_ALL,
- __END_SUBMENU__,
- SETUP_KEYBOARD_INPUT,
- SETUP_MIDI_INPUT,
- SETUP_MIDI_OUTPUT,
- CLONE_CHANNEL,
- DELETE_CHANNEL
+ EDIT_ACTIONS = 0,
+ CLEAR_ACTIONS,
+ CLEAR_ACTIONS_ALL,
+ __END_CLEAR_ACTION_SUBMENU__,
+ SETUP_KEYBOARD_INPUT,
+ SETUP_MIDI_INPUT,
+ SETUP_MIDI_OUTPUT,
+ RESIZE,
+ RESIZE_H1,
+ RESIZE_H2,
+ RESIZE_H3,
+ RESIZE_H4,
+ __END_RESIZE_SUBMENU__,
+ CLONE_CHANNEL,
+ DELETE_CHANNEL
};
void menuCallback(Fl_Widget *w, void *v)
{
- geMidiChannel *gch = static_cast<geMidiChannel*>(w);
- Menu selectedItem = (Menu) (intptr_t) v;
-
- switch (selectedItem)
- {
- case Menu::CLEAR_ACTIONS:
- case Menu::__END_SUBMENU__:
- break;
- case Menu::EDIT_ACTIONS:
- gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
- break;
- case Menu::CLEAR_ACTIONS_ALL:
- glue_clearAllActions(gch);
- break;
- case Menu::SETUP_KEYBOARD_INPUT:
- gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
- break;
- case Menu::SETUP_MIDI_INPUT:
- gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
- break;
- case Menu::SETUP_MIDI_OUTPUT:
- gu_openSubWindow(G_MainWin,
- new gdMidiOutputMidiCh(static_cast<MidiChannel*>(gch->ch)), 0);
- break;
- case Menu::CLONE_CHANNEL:
- glue_cloneChannel(gch->ch);
- break;
- case Menu::DELETE_CHANNEL:
- glue_deleteChannel(gch->ch);
- break;
- }
+ geMidiChannel *gch = static_cast<geMidiChannel*>(w);
+ Menu selectedItem = (Menu) (intptr_t) v;
+
+ switch (selectedItem)
+ {
+ case Menu::CLEAR_ACTIONS:
+ case Menu::__END_CLEAR_ACTION_SUBMENU__:
+ case Menu::RESIZE:
+ case Menu::__END_RESIZE_SUBMENU__:
+ break;
+ case Menu::EDIT_ACTIONS:
+ gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+ break;
+ case Menu::CLEAR_ACTIONS_ALL:
+ glue_clearAllActions(gch);
+ break;
+ case Menu::SETUP_KEYBOARD_INPUT:
+ gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
+ break;
+ case Menu::SETUP_MIDI_INPUT:
+ gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
+ break;
+ case Menu::SETUP_MIDI_OUTPUT:
+ gu_openSubWindow(G_MainWin,
+ new gdMidiOutputMidiCh(static_cast<MidiChannel*>(gch->ch)), 0);
+ break;
+ case Menu::RESIZE_H1:
+ gch->changeSize(G_GUI_CHANNEL_H_1);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ case Menu::RESIZE_H2:
+ gch->changeSize(G_GUI_CHANNEL_H_2);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ case Menu::RESIZE_H3:
+ gch->changeSize(G_GUI_CHANNEL_H_3);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ case Menu::RESIZE_H4:
+ gch->changeSize(G_GUI_CHANNEL_H_4);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ case Menu::CLONE_CHANNEL:
+ glue_cloneChannel(gch->ch);
+ break;
+ case Menu::DELETE_CHANNEL:
+ glue_deleteChannel(gch->ch);
+ break;
+ }
}
}; // {namespace}
begin();
#if defined(WITH_VST)
- int delta = 144; // (6 widgets * 20) + (6 paddings * 4)
+ int delta = 144; // (6 widgets * G_GUI_UNIT) + (6 paddings * 4)
#else
- int delta = 120; // (5 widgets * 20) + (5 paddings * 4)
+ int delta = 120; // (5 widgets * G_GUI_UNIT) + (5 paddings * 4)
#endif
- button = new geIdButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
- arm = new geButton(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
- mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, 20, "-- MIDI --");
- mute = new geButton(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
- solo = new geButton(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+ button = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+ arm = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
+ mainButton = new geMidiChannelButton(arm->x()+arm->w()+4, y(), w() - delta, H, "-- MIDI --");
+ mute = new geButton(mainButton->x()+mainButton->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", muteOff_xpm, muteOn_xpm);
+ solo = new geButton(mute->x()+mute->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", soloOff_xpm, soloOn_xpm);
#if defined(WITH_VST)
- fx = new geStatusButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
- vol = new geDial(fx->x()+fx->w()+4, y(), 20, 20);
+ fx = new geStatusButton(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+ vol = new geDial(fx->x()+fx->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
#else
- vol = new geDial(solo->x()+solo->w()+4, y(), 20, 20);
+ vol = new geDial(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
#endif
end();
- resizable(mainButton);
+ resizable(mainButton);
update();
vol->callback(cb_changeVol, (void*)this);
ch->guiChannel = this;
+
+ changeSize(H); // Update size dynamically
}
{"Setup keyboard input...", 0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
{"Setup MIDI input...", 0, menuCallback, (void*) Menu::SETUP_MIDI_INPUT},
{"Setup MIDI output...", 0, menuCallback, (void*) Menu::SETUP_MIDI_OUTPUT},
- {"Clone channel", 0, menuCallback, (void*) Menu::CLONE_CHANNEL},
- {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
+ {"Resize", 0, menuCallback, (void*) Menu::RESIZE, FL_SUBMENU},
+ {"Normal", 0, menuCallback, (void*) Menu::RESIZE_H1},
+ {"Medium", 0, menuCallback, (void*) Menu::RESIZE_H2},
+ {"Large", 0, menuCallback, (void*) Menu::RESIZE_H3},
+ {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
+ {0},
+ {"Clone channel", 0, menuCallback, (void*) Menu::CLONE_CHANNEL},
+ {"Delete channel", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
{0}
};
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);
- if (m)
- m->do_callback(this, m->user_data());
- return;
+ 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::resize(int X, int Y, int W, int H)
{
- geChannel::resize(X, Y, W, H);
+ geChannel::resize(X, Y, W, H);
arm->hide();
#ifdef WITH_VST
geMidiChannel(int x, int y, int w, int h, MidiChannel *ch);
- void reset ();
- void update ();
- void refresh ();
- int keyPress(int event); // TODO - move to base class
- void resize (int x, int y, int w, int h);
+ void resize(int x, int y, int w, int h) override;
+
+ void reset() override;
+ void update() override;
+ void refresh() override;
+
+ int keyPress(int event); // TODO - move to base class
};
#include "channelMode.h"
#include "sampleChannelButton.h"
#include "keyboard.h"
+#include "column.h"
#include "sampleChannel.h"
-extern gdMainWindow *G_MainWin;
+extern gdMainWindow* G_MainWin;
using namespace giada::m;
{
enum class Menu
{
- INPUT_MONITOR = 0,
- LOAD_SAMPLE,
- EXPORT_SAMPLE,
- SETUP_KEYBOARD_INPUT,
- SETUP_MIDI_INPUT,
- SETUP_MIDI_OUTPUT,
- EDIT_SAMPLE,
- EDIT_ACTIONS,
- CLEAR_ACTIONS,
- CLEAR_ACTIONS_ALL,
- CLEAR_ACTIONS_MUTE,
- CLEAR_ACTIONS_VOLUME,
- CLEAR_ACTIONS_START_STOP,
- __END_SUBMENU__,
- CLONE_CHANNEL,
- FREE_CHANNEL,
- DELETE_CHANNEL
+ INPUT_MONITOR = 0,
+ LOAD_SAMPLE,
+ EXPORT_SAMPLE,
+ SETUP_KEYBOARD_INPUT,
+ SETUP_MIDI_INPUT,
+ SETUP_MIDI_OUTPUT,
+ EDIT_SAMPLE,
+ EDIT_ACTIONS,
+ CLEAR_ACTIONS,
+ CLEAR_ACTIONS_ALL,
+ CLEAR_ACTIONS_MUTE,
+ CLEAR_ACTIONS_VOLUME,
+ CLEAR_ACTIONS_START_STOP,
+ __END_CLEAR_ACTIONS_SUBMENU__,
+ RESIZE,
+ RESIZE_H1,
+ RESIZE_H2,
+ RESIZE_H3,
+ RESIZE_H4,
+ __END_RESIZE_SUBMENU__,
+ CLONE_CHANNEL,
+ FREE_CHANNEL,
+ DELETE_CHANNEL
};
/* -------------------------------------------------------------------------- */
-void menuCallback(Fl_Widget *w, void *v)
+void menuCallback(Fl_Widget* w, void* v)
{
- geSampleChannel *gch = static_cast<geSampleChannel*>(w);
- Menu selectedItem = (Menu) (intptr_t) v;
-
- switch (selectedItem) {
- case Menu::INPUT_MONITOR: {
- glue_toggleInputMonitor(gch->ch);
- break;
- }
- case Menu::LOAD_SAMPLE: {
- gdWindow *w = new gdBrowserLoad(conf::browserX, conf::browserY,
- conf::browserW, conf::browserH, "Browse sample",
- conf::samplePath.c_str(), glue_loadSample, gch->ch);
- gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
- break;
- }
- case Menu::EXPORT_SAMPLE: {
- gdWindow *w = new gdBrowserSave(conf::browserX, conf::browserY,
- conf::browserW, conf::browserH, "Save sample",
- conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
- gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
- break;
- }
- case Menu::SETUP_KEYBOARD_INPUT: {
- new gdKeyGrabber(gch->ch); // FIXME - use gu_openSubWindow
- break;
- }
- case Menu::SETUP_MIDI_INPUT: {
- gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
- break;
- }
- case Menu::SETUP_MIDI_OUTPUT: {
- gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(static_cast<SampleChannel*>(gch->ch)), 0);
- break;
- }
- case Menu::EDIT_SAMPLE: {
- gu_openSubWindow(G_MainWin, new gdSampleEditor(static_cast<SampleChannel*>(gch->ch)), WID_SAMPLE_EDITOR);
- break;
- }
- case Menu::EDIT_ACTIONS: {
- gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
- break;
- }
- case Menu::CLEAR_ACTIONS:
- case Menu::__END_SUBMENU__:
- break;
- case Menu::CLEAR_ACTIONS_ALL: {
- glue_clearAllActions(gch);
- break;
- }
- case Menu::CLEAR_ACTIONS_MUTE: {
- glue_clearMuteActions(gch);
- break;
- }
- case Menu::CLEAR_ACTIONS_VOLUME: {
- glue_clearVolumeActions(gch);
- break;
- }
- case Menu::CLEAR_ACTIONS_START_STOP: {
- glue_clearStartStopActions(gch);
- break;
- }
- case Menu::CLONE_CHANNEL: {
- glue_cloneChannel(gch->ch);
- break;
- }
- case Menu::FREE_CHANNEL: {
- glue_freeChannel(gch->ch);
- break;
- }
- case Menu::DELETE_CHANNEL: {
- glue_deleteChannel(gch->ch);
- break;
- }
- }
+ geSampleChannel* gch = static_cast<geSampleChannel*>(w);
+ Menu selectedItem = (Menu) (intptr_t) v;
+
+ switch (selectedItem) {
+ case Menu::INPUT_MONITOR: {
+ glue_toggleInputMonitor(gch->ch);
+ break;
+ }
+ case Menu::LOAD_SAMPLE: {
+ gdWindow *w = new gdBrowserLoad(conf::browserX, conf::browserY,
+ conf::browserW, conf::browserH, "Browse sample",
+ conf::samplePath.c_str(), glue_loadSample, gch->ch);
+ gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+ break;
+ }
+ case Menu::EXPORT_SAMPLE: {
+ gdWindow *w = new gdBrowserSave(conf::browserX, conf::browserY,
+ conf::browserW, conf::browserH, "Save sample",
+ conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
+ gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+ break;
+ }
+ case Menu::SETUP_KEYBOARD_INPUT: {
+ new gdKeyGrabber(gch->ch); // FIXME - use gu_openSubWindow
+ break;
+ }
+ case Menu::SETUP_MIDI_INPUT: {
+ gu_openSubWindow(G_MainWin, new gdMidiInputChannel(gch->ch), 0);
+ break;
+ }
+ case Menu::SETUP_MIDI_OUTPUT: {
+ gu_openSubWindow(G_MainWin, new gdMidiOutputSampleCh(static_cast<SampleChannel*>(gch->ch)), 0);
+ break;
+ }
+ case Menu::EDIT_SAMPLE: {
+ gu_openSubWindow(G_MainWin, new gdSampleEditor(static_cast<SampleChannel*>(gch->ch)), WID_SAMPLE_EDITOR);
+ break;
+ }
+ case Menu::EDIT_ACTIONS: {
+ gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
+ break;
+ }
+ case Menu::CLEAR_ACTIONS:
+ case Menu::RESIZE:
+ case Menu::__END_CLEAR_ACTIONS_SUBMENU__:
+ case Menu::__END_RESIZE_SUBMENU__:
+ break;
+ case Menu::CLEAR_ACTIONS_ALL: {
+ glue_clearAllActions(gch);
+ break;
+ }
+ case Menu::CLEAR_ACTIONS_MUTE: {
+ glue_clearMuteActions(gch);
+ break;
+ }
+ case Menu::CLEAR_ACTIONS_VOLUME: {
+ glue_clearVolumeActions(gch);
+ break;
+ }
+ case Menu::CLEAR_ACTIONS_START_STOP: {
+ glue_clearStartStopActions(gch);
+ break;
+ }
+ case Menu::RESIZE_H1: {
+ gch->changeSize(G_GUI_CHANNEL_H_1);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ }
+ case Menu::RESIZE_H2: {
+ gch->changeSize(G_GUI_CHANNEL_H_2);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ }
+ case Menu::RESIZE_H3: {
+ gch->changeSize(G_GUI_CHANNEL_H_3);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ }
+ case Menu::RESIZE_H4: {
+ gch->changeSize(G_GUI_CHANNEL_H_4);
+ static_cast<geColumn*>(gch->parent())->repositionChannels();
+ break;
+ }
+ case Menu::CLONE_CHANNEL: {
+ glue_cloneChannel(gch->ch);
+ break;
+ }
+ case Menu::FREE_CHANNEL: {
+ glue_freeChannel(gch->ch);
+ break;
+ }
+ case Menu::DELETE_CHANNEL: {
+ glue_deleteChannel(gch->ch);
+ break;
+ }
+ }
}
}; // {namespace}
/* -------------------------------------------------------------------------- */
-geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel *ch)
- : geChannel(X, Y, W, H, CHANNEL_SAMPLE, (Channel*) ch)
+geSampleChannel::geSampleChannel(int X, int Y, int W, int H, SampleChannel* ch)
+ : geChannel(X, Y, W, H, CHANNEL_SAMPLE, ch)
{
begin();
- button = new geIdButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm);
- arm = new geButton(button->x()+button->w()+4, y(), 20, 20, "", armOff_xpm, armOn_xpm);
- status = new geChannelStatus(arm->x()+arm->w()+4, y(), 20, 20, ch);
- mainButton = new geSampleChannelButton(status->x()+status->w()+4, y(), 20, 20, "-- no sample --");
- readActions = new geButton(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm);
- modeBox = new geChannelMode(readActions->x()+readActions->w()+4, y(), 20, 20, ch);
- mute = new geButton(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm);
- solo = new geButton(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm);
+ button = new geIdButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, "", channelStop_xpm, channelPlay_xpm);
+ arm = new geButton(button->x()+button->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
+ status = new geChannelStatus(arm->x()+arm->w()+4, y(), G_GUI_UNIT, H, ch);
+ mainButton = new geSampleChannelButton(status->x()+status->w()+4, y(), G_GUI_UNIT, H, "-- no sample --");
+ readActions = new geButton(mainButton->x()+mainButton->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", readActionOff_xpm, readActionOn_xpm);
+ modeBox = new geChannelMode(readActions->x()+readActions->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, ch);
+ mute = new geButton(modeBox->x()+modeBox->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", muteOff_xpm, muteOn_xpm);
+ solo = new geButton(mute->x()+mute->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, "", soloOff_xpm, soloOn_xpm);
#ifdef WITH_VST
- fx = new geStatusButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm);
- vol = new geDial(fx->x()+fx->w()+4, y(), 20, 20);
+ fx = new geStatusButton(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+ vol = new geDial(fx->x()+fx->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
#else
- vol = new geDial(solo->x()+solo->w()+4, y(), 20, 20);
+ vol = new geDial(solo->x()+solo->w()+4, y(), G_GUI_UNIT, G_GUI_UNIT);
#endif
end();
- resizable(mainButton);
+ resizable(mainButton);
update();
vol->callback(cb_changeVol, (void*)this);
ch->guiChannel = this;
+
+ changeSize(H); // Update size dynamically
}
/* -------------------------------------------------------------------------- */
-void geSampleChannel::cb_button (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_button(); }
-void geSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_openMenu(); }
-void geSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((geSampleChannel*)p)->__cb_readActions(); }
+void geSampleChannel::cb_button (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_button(); }
+void geSampleChannel::cb_openMenu (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_openMenu(); }
+void geSampleChannel::cb_readActions (Fl_Widget* v, void* p) { ((geSampleChannel*)p)->__cb_readActions(); }
/* -------------------------------------------------------------------------- */
Fl_Menu_Item rclick_menu[] = {
{"Input monitor", 0, menuCallback, (void*) Menu::INPUT_MONITOR,
- FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
+ FL_MENU_TOGGLE | FL_MENU_DIVIDER | (static_cast<SampleChannel*>(ch)->inputMonitor ? FL_MENU_VALUE : 0)},
{"Load new sample...", 0, menuCallback, (void*) Menu::LOAD_SAMPLE},
{"Export sample to file...", 0, menuCallback, (void*) Menu::EXPORT_SAMPLE},
{"Setup keyboard input...", 0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
{"Volume", 0, menuCallback, (void*) Menu::CLEAR_ACTIONS_VOLUME},
{"Start/Stop", 0, menuCallback, (void*) Menu::CLEAR_ACTIONS_START_STOP},
{0},
+ {"Resize", 0, menuCallback, (void*) Menu::RESIZE, FL_SUBMENU},
+ {"Normal", 0, menuCallback, (void*) Menu::RESIZE_H1},
+ {"Medium", 0, menuCallback, (void*) Menu::RESIZE_H2},
+ {"Large", 0, menuCallback, (void*) Menu::RESIZE_H3},
+ {"X-Large", 0, menuCallback, (void*) Menu::RESIZE_H4},
+ {0},
{"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::CLEAR_ACTIONS].deactivate();
/* No 'clear start/stop actions' for those channels in loop mode: they cannot
- have start/stop actions. */
+ have start/stop actions. */
if (static_cast<SampleChannel*>(ch)->mode & LOOP_ANY)
rclick_menu[(int) Menu::CLEAR_ACTIONS_START_STOP].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);
- if (m)
- m->do_callback(this, m->user_data());
- return;
+ 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 geSampleChannel::__cb_readActions()
{
- glue_startStopReadingRecs((SampleChannel*) ch);
+ glue_startStopReadingRecs(static_cast<SampleChannel*>(ch));
}
void geSampleChannel::refresh()
{
- if (!mainButton->visible()) // mainButton invisible? status too (see below)
- return;
+ if (!mainButton->visible()) // mainButton invisible? status too (see below)
+ return;
setColorsByStatus(ch->status, ch->recStatus);
- if (((SampleChannel*) ch)->wave != nullptr) {
+ if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
if (mixer::recording && ch->armed)
mainButton->setInputRecordMode();
if (recorder::active) {
{
hideActionButton();
mainButton->setDefaultMode("-- no sample --");
- mainButton->redraw();
+ mainButton->redraw();
status->redraw();
}
mainButton->label("* file not found! *");
break;
default:
- mainButton->label(((SampleChannel*) ch)->wave->getName().c_str());
+ mainButton->label(static_cast<SampleChannel*>(ch)->wave->getName().c_str());
break;
}
/* updates modebox */
- modeBox->value(((SampleChannel*) ch)->mode);
+ modeBox->value(static_cast<SampleChannel*>(ch)->mode);
modeBox->redraw();
/* update volumes+mute+solo */
void geSampleChannel::showActionButton()
{
- readActions->value(((SampleChannel*) ch)->readActions);
+ readActions->value(static_cast<SampleChannel*>(ch)->readActions);
readActions->show();
packWidgets();
redraw();
void geSampleChannel::resize(int X, int Y, int W, int H)
{
- geChannel::resize(X, Y, W, H);
+ geChannel::resize(X, Y, W, H);
arm->hide();
modeBox->hide();
packWidgets();
}
+
+
+void geSampleChannel::changeSize(int H)
+{
+ geChannel::changeSize(H);
+
+ int Y = y() + (H / 2 - (G_GUI_UNIT / 2));
+
+ status->resize(x(), Y, w(), G_GUI_UNIT);
+ modeBox->resize(x(), Y, w(), G_GUI_UNIT);
+ readActions->resize(x(), Y, w(), G_GUI_UNIT);
+}
\ 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);
- static void cb_readActions (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);
+ static void cb_readActions(Fl_Widget* v, void* p);
+ void __cb_button ();
+ void __cb_openMenu ();
+ void __cb_readActions();
public:
- geSampleChannel(int x, int y, int w, int h, SampleChannel *ch);
+ geSampleChannel(int x, int y, int w, int h, SampleChannel* ch);
+
+ void resize(int x, int y, int w, int h) override;
+
+ void reset() override;
+ void update() override;
+ void refresh() override;
- void reset ();
- void update ();
- void refresh ();
- void resize (int x, int y, int w, int h);
+ void changeSize(int h);
/* show/hideActionButton
Adds or removes 'R' button when actions are available. */
void showActionButton();
void hideActionButton();
- geChannelMode *modeBox;
- geButton *readActions;
+ geChannelMode* modeBox;
+ geButton* readActions;
};
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())).c_str());
if (result != G_RES_OK)
G_MainWin->keyboard->printChannelMessage(result);
ret = 1;
using namespace giada::m;
-gePitchTool::gePitchTool(int x, int y, SampleChannel *ch)
+gePitchTool::gePitchTool(int x, int y, SampleChannel* ch)
: Fl_Group(x, y, 600, 20),
ch (ch)
{
/* -------------------------------------------------------------------------- */
-void gePitchTool::cb_setPitch (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitch(); }
-void gePitchTool::cb_setPitchToBar (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchToBar(); }
-void gePitchTool::cb_setPitchToSong(Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchToSong(); }
-void gePitchTool::cb_setPitchHalf (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchHalf(); }
-void gePitchTool::cb_setPitchDouble(Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchDouble(); }
-void gePitchTool::cb_resetPitch (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_resetPitch(); }
-void gePitchTool::cb_setPitchNum (Fl_Widget *w, void *p) { ((gePitchTool*)p)->__cb_setPitchNum(); }
+void gePitchTool::cb_setPitch (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitch(); }
+void gePitchTool::cb_setPitchToBar (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToBar(); }
+void gePitchTool::cb_setPitchToSong(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchToSong(); }
+void gePitchTool::cb_setPitchHalf (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchHalf(); }
+void gePitchTool::cb_setPitchDouble(Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchDouble(); }
+void gePitchTool::cb_resetPitch (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_resetPitch(); }
+void gePitchTool::cb_setPitchNum (Fl_Widget* w, void* p) { ((gePitchTool*)p)->__cb_setPitchNum(); }
/* -------------------------------------------------------------------------- */
void gePitchTool::__cb_setPitchToBar()
{
- glue_setPitch(ch, ch->getEnd() / (float) clock::getFramesPerBar());
+ // TODO - opaque channel's count
+ glue_setPitch(ch, (ch->getEnd()*2) / (float) clock::getFramesPerBar());
}
void gePitchTool::__cb_setPitchToSong()
{
- glue_setPitch(ch, ch->getEnd() / (float) clock::getTotalFrames());
+ // TODO - opaque channel's count
+ glue_setPitch(ch, (ch->getEnd()*2) / (float) clock::getTotalFrames());
}
void geRangeTool::__cb_setChanPos()
{
- sampleEditor::setBeginEndChannel(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
+ sampleEditor::setBeginEnd(m_ch, atoi(m_begin->value()), atoi(m_end->value()));
static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
}
void geRangeTool::__cb_resetStartEnd()
{
- sampleEditor::setBeginEndChannel(m_ch, 0, m_ch->wave->getSize() - 1);
+ sampleEditor::setBeginEnd(m_ch, 0, m_ch->wave->getSize() - 1);
static_cast<gdSampleEditor*>(window())->waveTools->updateWaveform();
}
{
enum class Menu
{
- CUT = 0,
- TRIM,
- SILENCE,
- FADE_IN,
- FADE_OUT,
- SMOOTH_EDGES,
- SET_START_END
+ CUT = 0,
+ COPY,
+ PASTE,
+ TRIM,
+ SILENCE,
+ REVERSE,
+ NORMALIZE,
+ FADE_IN,
+ FADE_OUT,
+ SMOOTH_EDGES,
+ SET_BEGIN_END,
+ TO_NEW_CHANNEL
};
void menuCallback(Fl_Widget* w, void* v)
{
- geWaveTools* wavetools = static_cast<geWaveTools*>(w);
- Menu selectedItem = (Menu) (intptr_t) v;
-
- int a = wavetools->waveform->getSelectionA();
- int b = wavetools->waveform->getSelectionB();
-
- switch (selectedItem) {
- case Menu::CUT:
- c::sampleEditor::cut(wavetools->ch, a, b);
- break;
- case Menu::TRIM:
- c::sampleEditor::trim(wavetools->ch, a, b);
- break;
- case Menu::SILENCE:
- c::sampleEditor::silence(wavetools->ch, a, b);
- break;
- case Menu::FADE_IN:
- c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_IN);
- break;
- case Menu::FADE_OUT:
- c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_OUT);
- break;
- case Menu::SMOOTH_EDGES:
- c::sampleEditor::smoothEdges(wavetools->ch, a, b);
- break;
- case Menu::SET_START_END:
- c::sampleEditor::setStartEnd(wavetools->ch, a, b);
- break;
- }
+ geWaveTools* wavetools = static_cast<geWaveTools*>(w);
+ Menu selectedItem = (Menu) (intptr_t) v;
+
+ int a = wavetools->waveform->getSelectionA();
+ int b = wavetools->waveform->getSelectionB();
+
+ switch (selectedItem) {
+ case Menu::CUT:
+ c::sampleEditor::cut(wavetools->ch, a, b);
+ break;
+ case Menu::COPY:
+ c::sampleEditor::copy(wavetools->ch, a, b);
+ break;
+ case Menu::PASTE:
+ c::sampleEditor::paste(wavetools->ch, a);
+ break;
+ case Menu::TRIM:
+ c::sampleEditor::trim(wavetools->ch, a, b);
+ break;
+ case Menu::SILENCE:
+ c::sampleEditor::silence(wavetools->ch, a, b);
+ break;
+ case Menu::REVERSE:
+ c::sampleEditor::reverse(wavetools->ch, a, b);
+ break;
+ case Menu::NORMALIZE:
+ c::sampleEditor::normalizeHard(wavetools->ch, a, b);
+ break;
+ case Menu::FADE_IN:
+ c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_IN);
+ break;
+ case Menu::FADE_OUT:
+ c::sampleEditor::fade(wavetools->ch, a, b, m::wfx::FADE_OUT);
+ break;
+ case Menu::SMOOTH_EDGES:
+ c::sampleEditor::smoothEdges(wavetools->ch, a, b);
+ break;
+ case Menu::SET_BEGIN_END:
+ c::sampleEditor::setBeginEnd(wavetools->ch, a, b);
+ break;
+ case Menu::TO_NEW_CHANNEL:
+ c::sampleEditor::toNewChannel(wavetools->ch, a, b);
+ break;
+ }
}
}; // {anonymous}
geWaveTools::geWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l)
: Fl_Scroll(x, y, w, h, l),
- ch (ch)
+ ch (ch)
{
type(Fl_Scroll::HORIZONTAL_ALWAYS);
hscrollbar.color(G_COLOR_GREY_2);
void geWaveTools::openMenu()
{
- if (!waveform->isSelected())
- return;
-
Fl_Menu_Item menu[] = {
- {"Cut", 0, menuCallback, (void*) Menu::CUT},
- {"Trim", 0, menuCallback, (void*) Menu::TRIM},
- {"Silence", 0, menuCallback, (void*) Menu::SILENCE},
- {"Fade in", 0, menuCallback, (void*) Menu::FADE_IN},
- {"Fade out", 0, menuCallback, (void*) Menu::FADE_OUT},
- {"Smooth edges", 0, menuCallback, (void*) Menu::SMOOTH_EDGES},
- {"Set start/end here", 0, menuCallback, (void*) Menu::SET_START_END},
- {0}
+ {"Cut", 0, menuCallback, (void*) Menu::CUT},
+ {"Copy", 0, menuCallback, (void*) Menu::COPY},
+ {"Paste", 0, menuCallback, (void*) Menu::PASTE},
+ {"Trim", 0, menuCallback, (void*) Menu::TRIM},
+ {"Silence", 0, menuCallback, (void*) Menu::SILENCE},
+ {"Reverse", 0, menuCallback, (void*) Menu::REVERSE},
+ {"Normalize", 0, menuCallback, (void*) Menu::NORMALIZE},
+ {"Fade in", 0, menuCallback, (void*) Menu::FADE_IN},
+ {"Fade out", 0, menuCallback, (void*) Menu::FADE_OUT},
+ {"Smooth edges", 0, menuCallback, (void*) Menu::SMOOTH_EDGES},
+ {"Set begin/end here", 0, menuCallback, (void*) Menu::SET_BEGIN_END},
+ {"Copy to new channel", 0, menuCallback, (void*) Menu::TO_NEW_CHANNEL},
+ {0}
};
- if (ch->status == STATUS_PLAY) {
- menu[(int)Menu::CUT].deactivate();
- menu[(int)Menu::TRIM].deactivate();
- }
+ if (ch->status == STATUS_PLAY) {
+ menu[(int)Menu::CUT].deactivate();
+ menu[(int)Menu::TRIM].deactivate();
+ }
+ if (!waveform->isSelected()) {
+ menu[(int)Menu::CUT].deactivate();
+ menu[(int)Menu::COPY].deactivate();
+ menu[(int)Menu::TRIM].deactivate();
+ menu[(int)Menu::SILENCE].deactivate();
+ menu[(int)Menu::REVERSE].deactivate();
+ menu[(int)Menu::NORMALIZE].deactivate();
+ menu[(int)Menu::FADE_IN].deactivate();
+ menu[(int)Menu::FADE_OUT].deactivate();
+ menu[(int)Menu::SMOOTH_EDGES].deactivate();
+ menu[(int)Menu::SET_BEGIN_END].deactivate();
+ menu[(int)Menu::TO_NEW_CHANNEL].deactivate();
+ }
Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50);
b->box(G_CUSTOM_BORDER_BOX);
b->color(G_COLOR_GREY_2);
const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b);
- if (m)
- m->do_callback(this, m->user_data());
- return;
+ if (m)
+ m->do_callback(this, m->user_data());
+ return;
}
geWaveform::geWaveform(int x, int y, int w, int h, SampleChannel* ch, const char* l)
: Fl_Widget (x, y, w, h, l),
- m_selection {},
- m_ch (ch),
- m_chanStart (0),
- m_chanStartLit(false),
- m_chanEnd (0),
- m_chanEndLit (false),
- m_pushed (false),
- m_dragged (false),
- m_resizedA (false),
- m_resizedB (false),
- m_ratio (0.0f)
+ m_selection {},
+ m_ch (ch),
+ m_chanStart (0),
+ m_chanStartLit(false),
+ m_chanEnd (0),
+ m_chanEndLit (false),
+ m_pushed (false),
+ m_dragged (false),
+ m_resizedA (false),
+ m_resizedB (false),
+ m_ratio (0.0f)
{
- m_data.sup = nullptr;
- m_data.inf = nullptr;
- m_data.size = 0;
+ m_data.sup = nullptr;
+ m_data.inf = nullptr;
+ m_data.size = 0;
- m_grid.snap = conf::sampleEditorGridOn;
- m_grid.level = conf::sampleEditorGridVal;
+ m_grid.snap = conf::sampleEditorGridOn;
+ m_grid.level = conf::sampleEditorGridVal;
- alloc(w);
+ alloc(w);
}
geWaveform::~geWaveform()
{
- freeData();
+ freeData();
}
void geWaveform::freeData()
{
- if (m_data.sup) {
- delete[] m_data.sup;
- delete[] m_data.inf;
- m_data.sup = nullptr;
- m_data.inf = nullptr;
- m_data.size = 0;
- }
- m_grid.points.clear();
+ if (m_data.sup) {
+ delete[] m_data.sup;
+ delete[] m_data.inf;
+ m_data.sup = nullptr;
+ m_data.inf = nullptr;
+ m_data.size = 0;
+ }
+ m_grid.points.clear();
}
int geWaveform::alloc(int datasize, bool force)
{
- Wave* wave = m_ch->wave;
+ Wave* wave = m_ch->wave;
- m_ratio = wave->getSize() / (float) datasize;
+ m_ratio = wave->getSize() / (float) datasize;
- /* Limit 1:1 drawing (to avoid sub-frame drawing) by keeping m_ratio >= 1. */
+ /* Limit 1:1 drawing (to avoid sub-frame drawing) by keeping m_ratio >= 1. */
- if (m_ratio < 1) {
- datasize = wave->getSize();
- m_ratio = 1;
- }
+ if (m_ratio < 1) {
+ datasize = wave->getSize();
+ m_ratio = 1;
+ }
- if (datasize == m_data.size && !force)
- return 0;
+ if (datasize == m_data.size && !force)
+ return 0;
- freeData();
+ freeData();
- m_data.size = datasize;
- m_data.sup = new (std::nothrow) int[m_data.size];
- m_data.inf = new (std::nothrow) int[m_data.size];
+ m_data.size = datasize;
+ m_data.sup = new (std::nothrow) int[m_data.size];
+ m_data.inf = new (std::nothrow) int[m_data.size];
- if (!m_data.sup || !m_data.inf) {
- gu_log("[geWaveform::alloc] unable to allocate memory for the waveform!\n");
- return 0;
- }
+ if (!m_data.sup || !m_data.inf) {
+ gu_log("[geWaveform::alloc] unable to allocate memory for the waveform!\n");
+ return 0;
+ }
- gu_log("[geWaveform::alloc] %d pixels, %f m_ratio\n", m_data.size, m_ratio);
+ gu_log("[geWaveform::alloc] %d pixels, %f m_ratio\n", m_data.size, m_ratio);
- int offset = h() / 2;
- int zero = y() + offset; // center, zero amplitude (-inf dB)
+ int offset = h() / 2;
+ int zero = y() + offset; // center, zero amplitude (-inf dB)
- /* Frid frequency: store a grid point every 'gridFreq' frame (if grid is
- enabled). TODO - this will cause round off errors, since gridFreq is integer. */
+ /* Frid frequency: store a grid point every 'gridFreq' frame (if grid is
+ enabled). TODO - this will cause round off errors, since gridFreq is integer. */
- int gridFreq = m_grid.level != 0 ? wave->getSize() / m_grid.level : 0;
+ int gridFreq = m_grid.level != 0 ? wave->getSize() / m_grid.level : 0;
/* Resampling the waveform, hardcore way. Many thanks to
http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html */
- for (int i=0; i<m_data.size; i++) {
-
- /* Scan the original waveform in chunks [pc, pn]. */
+ for (int i=0; i<m_data.size; i++) {
+
+ /* Scan the original waveform in chunks [pc, pn]. */
- float pc = i * m_ratio; // current point
- float pn = (i+1) * m_ratio; // next point
+ int pc = i * m_ratio; // current point TODO - int until we switch to uint32_t for Wave size...
+ int pn = (i+1) * m_ratio; // next point TODO - int until we switch to uint32_t for Wave size...
- float peaksup = 0.0f;
- float peakinf = 0.0f;
+ float peaksup = 0.0f;
+ float peakinf = 0.0f;
- for (float k=pc; k<pn; k++) {
+ for (int k=pc; k<pn; k++) { // TODO - int until we switch to uint32_t for Wave size...
- if (k >= wave->getSize())
- continue;
+ if (k >= wave->getSize())
+ continue;
- /* Compute average of stereo signal. */
+ /* Compute average of stereo signal. */
float avg = 0.0f;
float* frame = wave->getFrame(k);
if (gridFreq != 0 && (int) k % gridFreq == 0 && k != 0)
m_grid.points.push_back(k);
- }
+ }
- m_data.sup[i] = zero - (peaksup * m_ch->getBoost() * offset);
- m_data.inf[i] = zero - (peakinf * m_ch->getBoost() * offset);
+ m_data.sup[i] = zero - (peaksup * m_ch->getBoost() * offset);
+ m_data.inf[i] = zero - (peakinf * m_ch->getBoost() * offset);
- // avoid window overflow
+ // avoid window overflow
- if (m_data.sup[i] < y()) m_data.sup[i] = y();
- if (m_data.inf[i] > y()+h()-1) m_data.inf[i] = y()+h()-1;
- }
+ if (m_data.sup[i] < y()) m_data.sup[i] = y();
+ if (m_data.inf[i] > y()+h()-1) m_data.inf[i] = y()+h()-1;
+ }
- recalcPoints();
- return 1;
+ recalcPoints();
+ return 1;
}
void geWaveform::recalcPoints()
{
- m_chanStart = m_ch->getBegin();
- m_chanEnd = m_ch->getEnd();
+ m_chanStart = m_ch->getBegin();
+ m_chanEnd = m_ch->getEnd();
}
void geWaveform::drawSelection()
{
- if (!isSelected())
- return;
+ if (!isSelected())
+ return;
- int a = frameToPixel(m_selection.a) + x();
- int b = frameToPixel(m_selection.b) + x();
+ int a = frameToPixel(m_selection.a) + x();
+ int b = frameToPixel(m_selection.b) + x();
- if (a < 0)
- a = 0;
- if (b >= w() + BORDER)
- b = w() + BORDER;
+ if (a < 0)
+ a = 0;
+ if (b >= w() + BORDER)
+ b = w() + BORDER;
- if (a < b)
- fl_rectf(a, y(), b-a, h(), G_COLOR_GREY_4);
- else
- fl_rectf(b, y(), a-b, h(), G_COLOR_GREY_4);
+ if (a < b)
+ fl_rectf(a, y(), b-a, h(), G_COLOR_GREY_4);
+ else
+ fl_rectf(b, y(), a-b, h(), G_COLOR_GREY_4);
}
void geWaveform::drawWaveform(int from, int to)
{
- int zero = y() + (h() / 2); // zero amplitude (-inf dB)
-
- fl_color(G_COLOR_BLACK);
- for (int i=from; i<to; i++) {
- if (i >= m_data.size)
- break;
- fl_line(i+x(), zero, i+x(), m_data.sup[i]);
- fl_line(i+x(), zero, i+x(), m_data.inf[i]);
- }
+ int zero = y() + (h() / 2); // zero amplitude (-inf dB)
+
+ fl_color(G_COLOR_BLACK);
+ for (int i=from; i<to; i++) {
+ if (i >= m_data.size)
+ break;
+ fl_line(i+x(), zero, i+x(), m_data.sup[i]);
+ fl_line(i+x(), zero, i+x(), m_data.inf[i]);
+ }
}
void geWaveform::drawStartEndPoints()
{
- /* print m_chanStart */
+ /* print m_chanStart */
- int lineX = frameToPixel(m_chanStart) + x();
+ int lineX = frameToPixel(m_chanStart) + x();
- if (m_chanStartLit) fl_color(G_COLOR_LIGHT_2);
- else fl_color(G_COLOR_LIGHT_1);
+ if (m_chanStartLit) fl_color(G_COLOR_LIGHT_2);
+ else fl_color(G_COLOR_LIGHT_1);
- /* vertical line */
+ /* vertical line */
- fl_line(lineX, y()+1, lineX, y()+h()-2);
+ fl_line(lineX, y()+1, lineX, y()+h()-2);
- /* print flag and avoid overflow */
+ /* print flag and avoid overflow */
- if (lineX+FLAG_WIDTH > w()+x()-2)
- fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
- else
- fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
+ if (lineX+FLAG_WIDTH > w()+x()-2)
+ fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
+ else
+ fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
- /* print m_chanEnd */
+ /* print m_chanEnd */
- lineX = frameToPixel(m_chanEnd) + x() - 1;
- if (m_chanEndLit) fl_color(G_COLOR_LIGHT_2);
- else fl_color(G_COLOR_LIGHT_1);
+ lineX = frameToPixel(m_chanEnd) + x() - 1;
+ if (m_chanEndLit) fl_color(G_COLOR_LIGHT_2);
+ else fl_color(G_COLOR_LIGHT_1);
- /* vertical line */
+ /* vertical line */
- fl_line(lineX, y()+1, lineX, y()+h()-2);
+ fl_line(lineX, y()+1, lineX, y()+h()-2);
- if (lineX-FLAG_WIDTH < x())
- fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
- else
- fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
+ if (lineX-FLAG_WIDTH < x())
+ fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
+ else
+ fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
}
void geWaveform::drawPlayHead()
{
- int p = frameToPixel(m_ch->getTrackerPreview()) + x();
- fl_color(G_COLOR_LIGHT_2);
- fl_line(p, y() + 1, p, y() + h() - 2);
+ int p = frameToPixel(m_ch->getTrackerPreview()) + x();
+ fl_color(G_COLOR_LIGHT_2);
+ fl_line(p, y() + 1, p, y() + h() - 2);
}
void geWaveform::draw()
{
- assert(m_data.sup != nullptr);
- assert(m_data.inf != nullptr);
+ assert(m_data.sup != nullptr);
+ assert(m_data.inf != nullptr);
- fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2); // blank canvas
+ fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2); // blank canvas
- /* Draw things from 'from' (offset driven by the scrollbar) to 'to' (width of
- parent window). We don't draw the entire waveform, only the visibile part. */
+ /* Draw things from 'from' (offset driven by the scrollbar) to 'to' (width of
+ parent window). We don't draw the entire waveform, only the visibile part. */
- int from = abs(x() - parent()->x());
- int to = from + parent()->w();
- if (x() + w() < parent()->w())
- to = x() + w() - BORDER;
+ int from = abs(x() - parent()->x());
+ int to = from + parent()->w();
+ if (x() + w() < parent()->w())
+ to = x() + w() - BORDER;
- drawSelection();
- drawWaveform(from, to);
- drawGrid(from, to);
- drawPlayHead();
+ drawSelection();
+ drawWaveform(from, to);
+ drawGrid(from, to);
+ drawPlayHead();
- fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border box
-
- drawStartEndPoints();
+ fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border box
+
+ drawStartEndPoints();
}
m_mouseX = pixelToFrame(Fl::event_x() - x());
m_mouseY = pixelToFrame(Fl::event_y() - y());
- switch (e) {
+ switch (e) {
- case FL_KEYDOWN: {
- if (Fl::event_key() == ' ')
- static_cast<gdSampleEditor*>(window())->__cb_togglePreview();
- else
- if (Fl::event_key() == FL_BackSpace)
+ case FL_KEYDOWN: {
+ if (Fl::event_key() == ' ')
+ static_cast<gdSampleEditor*>(window())->__cb_togglePreview();
+ else
+ if (Fl::event_key() == FL_BackSpace)
sampleEditor::rewindPreview(m_ch);
- return 1;
- }
-
- case FL_PUSH: {
-
- m_pushed = true;
-
- if (!mouseOnEnd() && !mouseOnStart()) {
- if (Fl::event_button3()) // let the parent (waveTools) handle this
- return 0;
- if (mouseOnSelectionA())
- m_resizedA = true;
- else
- if(mouseOnSelectionB())
- m_resizedB = true;
- else {
- m_dragged = true;
- m_selection.a = m_mouseX;
- m_selection.b = m_mouseX;
- }
- }
- return 1;
- }
-
- case FL_RELEASE: {
-
- sampleEditor::setPlayHead(m_ch, m_mouseX);
-
- /* If selection has been done (m_dragged or resized), make sure that point A
- is always lower than B. */
-
- if (m_dragged || m_resizedA || m_resizedB)
- fixSelection();
-
- /* Handle begin/end markers interaction. */
-
- if (m_chanStartLit || m_chanEndLit)
- sampleEditor::setBeginEndChannel(m_ch, m_chanStart, m_chanEnd);
-
- m_pushed = false;
- m_dragged = false;
- m_resizedA = false;
- m_resizedB = false;
-
- redraw();
- return 1;
- }
-
- case FL_ENTER: { // enables FL_DRAG
- return 1;
- }
-
- case FL_LEAVE: {
- if (m_chanStartLit || m_chanEndLit) {
- m_chanStartLit = false;
- m_chanEndLit = false;
- redraw();
- }
- return 1;
- }
-
- case FL_MOVE: {
-
- if (mouseOnStart()) {
- m_chanStartLit = true;
- redraw();
- }
- else
- if (m_chanStartLit) {
- m_chanStartLit = false;
- redraw();
- }
-
- if (mouseOnEnd()) {
- m_chanEndLit = true;
- redraw();
- }
- else
- if (m_chanEndLit) {
- m_chanEndLit = false;
- redraw();
- }
-
- if (mouseOnSelectionA() && isSelected())
- fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
- else
- if (mouseOnSelectionB() && isSelected())
- fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
- else
- fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-
- return 1;
- }
-
- case FL_DRAG: {
-
- /* here the mouse is on the m_chanStart tool */
-
- if (m_chanStartLit && m_pushed) {
-
- m_chanStart = snap(m_mouseX);
-
- if (m_chanStart < 0)
- m_chanStart = 0;
- else
- if (m_chanStart >= m_chanEnd)
- m_chanStart = m_chanEnd - 2;
-
- redraw();
- }
- else
- if (m_chanEndLit && m_pushed) {
-
- m_chanEnd = snap(m_mouseX);
-
- if (m_chanEnd > m_ch->wave->getSize())
- m_chanEnd = m_ch->wave->getSize();
- else
- if (m_chanEnd <= m_chanStart)
- m_chanEnd = m_chanStart + 2;
-
- redraw();
- }
-
- /* Here the mouse is on the waveform, i.e. a new selection has started. */
-
- else
- if (m_dragged) {
- m_selection.b = snap(m_mouseX);
- redraw();
- }
-
- /* here the mouse is on a selection boundary i.e. resize */
-
- else
- if (m_resizedA || m_resizedB) {
- int pos = snap(m_mouseX);
- m_resizedA ? m_selection.a = pos : m_selection.b = pos;
- redraw();
- }
-
- return 1;
- }
-
- default:
- return Fl_Widget::handle(e);
- }
+ return 1;
+ }
+
+ case FL_PUSH: {
+
+ if (Fl::event_clicks() > 0) {
+ selectAll();
+ return 1;
+ }
+
+ m_pushed = true;
+
+ if (!mouseOnEnd() && !mouseOnStart()) {
+ if (Fl::event_button3()) // let the parent (waveTools) handle this
+ return 0;
+ if (mouseOnSelectionA())
+ m_resizedA = true;
+ else
+ if(mouseOnSelectionB())
+ m_resizedB = true;
+ else {
+ m_dragged = true;
+ m_selection.a = m_mouseX;
+ m_selection.b = m_mouseX;
+ }
+ }
+ return 1;
+ }
+
+ case FL_RELEASE: {
+
+ sampleEditor::setPlayHead(m_ch, m_mouseX);
+
+ /* If selection has been done (m_dragged or resized), make sure that point A
+ is always lower than B. */
+
+ if (m_dragged || m_resizedA || m_resizedB)
+ fixSelection();
+
+ /* Handle begin/end markers interaction. */
+
+ if (m_chanStartLit || m_chanEndLit)
+ sampleEditor::setBeginEnd(m_ch, m_chanStart, m_chanEnd);
+
+ m_pushed = false;
+ m_dragged = false;
+ m_resizedA = false;
+ m_resizedB = false;
+
+ redraw();
+ return 1;
+ }
+
+ case FL_ENTER: { // enables FL_DRAG
+ return 1;
+ }
+
+ case FL_LEAVE: {
+ if (m_chanStartLit || m_chanEndLit) {
+ m_chanStartLit = false;
+ m_chanEndLit = false;
+ redraw();
+ }
+ return 1;
+ }
+
+ case FL_MOVE: {
+
+ if (mouseOnStart()) {
+ m_chanStartLit = true;
+ redraw();
+ }
+ else
+ if (m_chanStartLit) {
+ m_chanStartLit = false;
+ redraw();
+ }
+
+ if (mouseOnEnd()) {
+ m_chanEndLit = true;
+ redraw();
+ }
+ else
+ if (m_chanEndLit) {
+ m_chanEndLit = false;
+ redraw();
+ }
+
+ if (mouseOnSelectionA() && isSelected())
+ fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+ else
+ if (mouseOnSelectionB() && isSelected())
+ fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+ else
+ fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+
+ return 1;
+ }
+
+ case FL_DRAG: {
+
+ /* here the mouse is on the m_chanStart tool */
+
+ if (m_chanStartLit && m_pushed) {
+
+ m_chanStart = snap(m_mouseX);
+
+ if (m_chanStart < 0)
+ m_chanStart = 0;
+ else
+ if (m_chanStart >= m_chanEnd)
+ m_chanStart = m_chanEnd - 2;
+
+ redraw();
+ }
+ else
+ if (m_chanEndLit && m_pushed) {
+
+ m_chanEnd = snap(m_mouseX);
+
+ if (m_chanEnd > m_ch->wave->getSize())
+ m_chanEnd = m_ch->wave->getSize();
+ else
+ if (m_chanEnd <= m_chanStart)
+ m_chanEnd = m_chanStart + 2;
+
+ redraw();
+ }
+
+ /* Here the mouse is on the waveform, i.e. a new selection has started. */
+
+ else
+ if (m_dragged) {
+ m_selection.b = snap(m_mouseX);
+ redraw();
+ }
+
+ /* here the mouse is on a selection boundary i.e. resize */
+
+ else
+ if (m_resizedA || m_resizedB) {
+ int pos = snap(m_mouseX);
+ m_resizedA ? m_selection.a = pos : m_selection.b = pos;
+ redraw();
+ }
+
+ return 1;
+ }
+
+ default:
+ return Fl_Widget::handle(e);
+ }
}
return pos;
for (int pf : m_grid.points) {
if (pos >= pf - pixelToFrame(SNAPPING) &&
- pos <= pf + pixelToFrame(SNAPPING))
+ pos <= pf + pixelToFrame(SNAPPING))
{
return pf;
}
int mouseXp = frameToPixel(m_mouseX);
int mouseYp = frameToPixel(m_mouseY);
int chanStartP = frameToPixel(m_chanStart);
- return mouseXp - (FLAG_WIDTH / 2) > chanStartP - BORDER &&
- mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
- mouseYp > h() - FLAG_HEIGHT;
+ return mouseXp - (FLAG_WIDTH / 2) > chanStartP - BORDER &&
+ mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
+ mouseYp > h() - FLAG_HEIGHT;
}
int mouseXp = frameToPixel(m_mouseX);
int mouseYp = frameToPixel(m_mouseY);
int chanEndP = frameToPixel(m_chanEnd);
- return mouseXp - (FLAG_WIDTH / 2) >= chanEndP - BORDER - FLAG_WIDTH &&
- mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER &&
- mouseYp <= FLAG_HEIGHT + 1;
+ return mouseXp - (FLAG_WIDTH / 2) >= chanEndP - BORDER - FLAG_WIDTH &&
+ mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER &&
+ mouseYp <= FLAG_HEIGHT + 1;
}
{
int mouseXp = frameToPixel(m_mouseX);
int selAp = frameToPixel(m_selection.a);
- return mouseXp >= selAp - (FLAG_WIDTH / 2) && mouseXp <= selAp + (FLAG_WIDTH / 2);
+ return mouseXp >= selAp - (FLAG_WIDTH / 2) && mouseXp <= selAp + (FLAG_WIDTH / 2);
}
{
int mouseXp = frameToPixel(m_mouseX);
int selBp = frameToPixel(m_selection.b);
- return mouseXp >= selBp - (FLAG_WIDTH / 2) && mouseXp <= selBp + (FLAG_WIDTH / 2);
+ return mouseXp >= selBp - (FLAG_WIDTH / 2) && mouseXp <= selBp + (FLAG_WIDTH / 2);
}
int geWaveform::pixelToFrame(int p)
{
- if (p <= 0)
- return 0;
- if (p > m_data.size)
- return m_ch->wave->getSize() - 1;
- return p * m_ratio;
+ if (p <= 0)
+ return 0;
+ if (p > m_data.size)
+ return m_ch->wave->getSize() - 1;
+ return p * m_ratio;
}
int geWaveform::frameToPixel(int p)
{
- return ceil(p / m_ratio);
+ return ceil(p / m_ratio);
}
void geWaveform::fixSelection()
{
- if (m_selection.a > m_selection.b) // inverted m_selection
- std::swap(m_selection.a, m_selection.b);
- sampleEditor::setPlayHead(m_ch, m_selection.a);
+ if (m_selection.a > m_selection.b) // inverted m_selection
+ std::swap(m_selection.a, m_selection.b);
+ sampleEditor::setPlayHead(m_ch, m_selection.a);
}
void geWaveform::clearSel()
{
- m_selection.a = 0;
- m_selection.b = 0;
+ m_selection.a = 0;
+ m_selection.b = 0;
}
void geWaveform::setZoom(int type)
{
- if (!alloc(type == ZOOM_IN ? m_data.size * 2 : m_data.size / 2))
- return;
+ if (!alloc(type == ZOOM_IN ? m_data.size * 2 : m_data.size / 2))
+ return;
- size(m_data.size, h());
+ size(m_data.size, h());
- /* Zoom to cursor. */
+ /* Zoom to cursor. */
int newX = -frameToPixel(m_mouseX) + Fl::event_x();
if (newX > BORDER)
newX = BORDER;
position(newX, y());
- /* Avoid overflow when zooming out with scrollbar like that:
+ /* Avoid overflow when zooming out with scrollbar like that:
- |----------[scrollbar]|
+ |----------[scrollbar]|
- Offset vs smaller:
-
- |[wave------------| offset > 0 smaller = false
- |[wave----] | offset < 0, smaller = true
- |-------------] | offset < 0, smaller = false */
+ Offset vs smaller:
+
+ |[wave------------| offset > 0 smaller = false
+ |[wave----] | offset < 0, smaller = true
+ |-------------] | offset < 0, smaller = false */
- int parentW = parent()->w();
- int thisW = x() + w() - BORDER; // visible width, not full width
+ int parentW = parent()->w();
+ int thisW = x() + w() - BORDER; // visible width, not full width
- if (thisW < parentW)
- position(x() + parentW - thisW, y());
- if (smaller())
- stretchToWindow();
+ if (thisW < parentW)
+ position(x() + parentW - thisW, y());
+ if (smaller())
+ stretchToWindow();
- redraw();
+ redraw();
}
void geWaveform::stretchToWindow()
{
- int s = parent()->w();
- alloc(s);
- position(BORDER, y());
- size(s, h());
+ int s = parent()->w();
+ alloc(s);
+ position(BORDER, y());
+ size(s, h());
}
void geWaveform::refresh()
{
- alloc(m_data.size, true); // force
- redraw();
+ alloc(m_data.size, true); // force
+ redraw();
}
bool geWaveform::smaller()
{
- return w() < parent()->w();
+ return w() < parent()->w();
}
void geWaveform::setGridLevel(int l)
{
- m_grid.points.clear();
- m_grid.level = l;
- alloc(m_data.size, true); // force alloc
- redraw();
+ m_grid.points.clear();
+ m_grid.level = l;
+ alloc(m_data.size, true); // force alloc
+ redraw();
}
bool geWaveform::isSelected()
{
- return m_selection.a != m_selection.b;
+ return m_selection.a != m_selection.b;
}
int geWaveform::getSelectionA()
{
- return m_selection.a;
+ return m_selection.a;
}
int geWaveform::getSelectionB()
{
- return m_selection.b;
+ return m_selection.b;
}
+
+void geWaveform::selectAll()
+{
+ m_selection.a = 0;
+ m_selection.b = m_ch->wave->getSize() - 1;
+ redraw();
+}
Real graphic stuff from the underlying waveform. */
struct
- {
+ {
int* sup; // upper part of the waveform
int* inf; // lower part of the waveform
int size; // width of the waveform to draw (in pixel)
} m_data;
struct
- {
+ {
bool snap;
int level;
std::vector<int> points;
bool mouseOnSelectionA();
bool mouseOnSelectionB();
- int pixelToFrame(int p);
- int frameToPixel(int f);
+ int pixelToFrame(int p); // TODO - move these to utils::, will be needed in actionEditor
+ int frameToPixel(int f); // TODO - move these to utils::, will be needed in actionEditor
/* fixSelection
Helper function which flattens the selection if it was made from right to left
bool smaller();
- /* snap
- Snaps a point at 'pos' pixel. */
+ /* snap
+ Snaps a point at 'pos' pixel. */
+
+ int snap(int pos);
- int snap(int pos);
+ /* draw*
+ Drawing functions. */
- /* draw*
- Drawing functions. */
+ void drawSelection();
+ void drawWaveform(int from, int to);
+ void drawGrid(int from, int to);
+ void drawStartEndPoints();
+ void drawPlayHead();
- void drawSelection();
- void drawWaveform(int from, int to);
- void drawGrid(int from, int to);
- void drawStartEndPoints();
- void drawPlayHead();
+ void selectAll();
public:
void setGridLevel(int l);
- void setSnap(bool v);
- bool getSnap();
+ void setSnap(bool v);
+ bool getSnap();
int getSize();
/* isSelected
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 <chrono>
+#include <thread>
+#include "time.h"
+
+
+namespace giada {
+namespace u {
+namespace time
+{
+void sleep(int millisecs)
+{
+ std::this_thread::sleep_for(std::chrono::milliseconds(millisecs));
+}
+}}}; // giada::u::time::
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * utils
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * 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 G_UTILS_TIME_H
+#define G_UTILS_TIME_H
+
+
+namespace giada {
+namespace u {
+namespace time
+{
+void sleep(int millisecs);
+}}};
+
+
+#endif
\ No newline at end of file
TEST_CASE("Test Patch class")
{
- string filename = "./test-patch.json";
-
- SECTION("test write")
- {
- patch::action_t action1;
- patch::action_t action2;
- patch::channel_t channel1;
- patch::channel_t channel2;
- patch::column_t column;
+ string filename = "./test-patch.json";
+
+ SECTION("test write")
+ {
+ patch::action_t action1;
+ patch::action_t action2;
+ patch::channel_t channel1;
+ patch::column_t column;
#ifdef WITH_VST
- patch::plugin_t plugin1;
- patch::plugin_t plugin2;
- patch::plugin_t plugin3;
+ patch::plugin_t plugin1;
+ patch::plugin_t plugin2;
+ patch::plugin_t plugin3;
#endif
- action1.type = 0;
- action1.frame = 50000;
- action1.fValue = 0.3f;
- action1.iValue = 1000;
- action2.type = 2;
- action2.frame = 589;
- action2.fValue = 1.0f;
- action2.iValue = 130;
- channel1.actions.push_back(action1);
- channel1.actions.push_back(action2);
+ action1.type = 0;
+ action1.frame = 50000;
+ action1.fValue = 0.3f;
+ action1.iValue = 1000;
+ action2.type = 2;
+ action2.frame = 589;
+ action2.fValue = 1.0f;
+ action2.iValue = 130;
+ channel1.actions.push_back(action1);
+ channel1.actions.push_back(action2);
#ifdef WITH_VST
- plugin1.path = "/path/to/plugin1";
- plugin1.bypass = false;
- plugin1.params.push_back(0.0f);
- plugin1.params.push_back(0.1f);
- plugin1.params.push_back(0.2f);
- channel1.plugins.push_back(plugin1);
-
- plugin2.path = "/another/path/to/plugin2";
- plugin2.bypass = true;
- plugin2.params.push_back(0.6f);
- plugin2.params.push_back(0.6f);
- plugin2.params.push_back(0.6f);
- plugin2.params.push_back(0.0f);
- plugin2.params.push_back(1.0f);
- plugin2.params.push_back(1.0f);
- plugin2.params.push_back(0.333f);
- channel1.plugins.push_back(plugin2);
+ plugin1.path = "/path/to/plugin1";
+ plugin1.bypass = false;
+ plugin1.params.push_back(0.0f);
+ plugin1.params.push_back(0.1f);
+ plugin1.params.push_back(0.2f);
+ channel1.plugins.push_back(plugin1);
+
+ plugin2.path = "/another/path/to/plugin2";
+ plugin2.bypass = true;
+ plugin2.params.push_back(0.6f);
+ plugin2.params.push_back(0.6f);
+ plugin2.params.push_back(0.6f);
+ plugin2.params.push_back(0.0f);
+ plugin2.params.push_back(1.0f);
+ plugin2.params.push_back(1.0f);
+ plugin2.params.push_back(0.333f);
+ channel1.plugins.push_back(plugin2);
#endif
- channel1.type = CHANNEL_SAMPLE;
- channel1.index = 666;
- channel1.column = 0;
- channel1.mute = 0;
- channel1.mute_s = 0;
- channel1.solo = 0;
- channel1.volume = 1.0f;
- channel1.pan = 0.5f;
- channel1.midiIn = true;
- channel1.midiInKeyPress = UINT32_MAX; // check maximum value
- channel1.midiInKeyRel = 1;
- channel1.midiInKill = 2;
- channel1.midiInArm = 11;
- channel1.midiInVolume = 3;
- channel1.midiInMute = 4;
- channel1.midiInSolo = 5;
- channel1.midiOutL = true;
- channel1.midiOutLplaying = 7;
- channel1.midiOutLmute = 8;
- channel1.midiOutLsolo = 9;
- channel1.samplePath = "/tmp/test.wav";
- channel1.key = 666;
- channel1.mode = 0;
- channel1.begin = 0;
- channel1.end = 0;
- channel1.boost = 0;
- channel1.recActive = 0;
- channel1.pitch = 1.2f;
- channel1.midiInReadActions = 0;
- channel1.midiInPitch = 0;
- channel1.midiOut = 0;
- channel1.midiOutChan = 5;
- patch::channels.push_back(channel1);
-
- column.index = 0;
- column.width = 500;
- patch::columns.push_back(column);
-
- patch::header = "GPTCH";
- patch::version = "1.0";
- patch::versionMajor = 6;
- patch::versionMinor = 6;
- patch::versionPatch = 6;
- patch::name = "test patch";
- patch::bpm = 100.0f;
- patch::bars = 4;
- patch::beats = 23;
- patch::quantize = 1;
- patch::masterVolIn = 1.0f;
- patch::masterVolOut = 0.7f;
- patch::metronome = 0;
- patch::lastTakeId = 0;
- patch::samplerate = 44100;
+ channel1.type = CHANNEL_SAMPLE;
+ channel1.index = 666;
+ channel1.size = G_GUI_CHANNEL_H_1;
+ channel1.column = 0;
+ channel1.mute = 0;
+ channel1.mute_s = 0;
+ channel1.solo = 0;
+ channel1.volume = 1.0f;
+ channel1.pan = 0.5f;
+ channel1.midiIn = true;
+ channel1.midiInKeyPress = UINT32_MAX; // check maximum value
+ channel1.midiInKeyRel = 1;
+ channel1.midiInKill = 2;
+ channel1.midiInArm = 11;
+ channel1.midiInVolume = 3;
+ channel1.midiInMute = 4;
+ channel1.midiInSolo = 5;
+ channel1.midiOutL = true;
+ channel1.midiOutLplaying = 7;
+ channel1.midiOutLmute = 8;
+ channel1.midiOutLsolo = 9;
+ channel1.samplePath = "/tmp/test.wav";
+ channel1.key = 666;
+ channel1.mode = 0;
+ channel1.begin = 0;
+ channel1.end = 0;
+ channel1.boost = 0;
+ channel1.recActive = 0;
+ channel1.pitch = 1.2f;
+ channel1.midiInReadActions = 0;
+ channel1.midiInPitch = 0;
+ channel1.midiOut = 0;
+ channel1.midiOutChan = 5;
+ patch::channels.push_back(channel1);
+
+ column.index = 0;
+ column.width = 500;
+ patch::columns.push_back(column);
+
+ patch::header = "GPTCH";
+ patch::version = "1.0";
+ patch::versionMajor = 6;
+ patch::versionMinor = 6;
+ patch::versionPatch = 6;
+ patch::name = "test patch";
+ patch::bpm = 100.0f;
+ patch::bars = 4;
+ patch::beats = 23;
+ patch::quantize = 1;
+ patch::masterVolIn = 1.0f;
+ patch::masterVolOut = 0.7f;
+ patch::metronome = 0;
+ patch::lastTakeId = 0;
+ patch::samplerate = 44100;
#ifdef WITH_VST
- patch::masterInPlugins.push_back(plugin1);
- patch::masterOutPlugins.push_back(plugin2);
+ patch::masterInPlugins.push_back(plugin1);
+ patch::masterOutPlugins.push_back(plugin2);
#endif
- REQUIRE(patch::write(filename) == 1);
- }
-
- SECTION("test read")
- {
- REQUIRE(patch::read(filename) == PATCH_READ_OK);
- REQUIRE(patch::header == "GPTCH");
- REQUIRE(patch::version == "1.0");
- REQUIRE(patch::versionMajor == 6);
- REQUIRE(patch::versionMinor == 6);
- REQUIRE(patch::versionPatch == 6);
- REQUIRE(patch::name == "test patch");
- REQUIRE(patch::bpm == Approx(100.0f));
- REQUIRE(patch::bars == 4);
- REQUIRE(patch::beats == 23);
- REQUIRE(patch::quantize == 1);
- REQUIRE(patch::masterVolIn == Approx(1.0f));
- REQUIRE(patch::masterVolOut == Approx(0.7f));
- REQUIRE(patch::metronome == 0);
- REQUIRE(patch::lastTakeId == 0);
- REQUIRE(patch::samplerate == 44100);
-
- patch::column_t column0 = patch::columns.at(0);
- REQUIRE(column0.index == 0);
- REQUIRE(column0.width == 500);
-
- patch::channel_t channel0 = patch::channels.at(0);
- REQUIRE(channel0.type == CHANNEL_SAMPLE);
- REQUIRE(channel0.index == 666);
- REQUIRE(channel0.column == 0);
- REQUIRE(channel0.mute == 0);
- REQUIRE(channel0.mute_s == 0);
- REQUIRE(channel0.solo == 0);
- REQUIRE(channel0.volume == Approx(1.0f));
- REQUIRE(channel0.pan == Approx(0.5f));
- REQUIRE(channel0.midiIn == true);
- REQUIRE(channel0.midiInKeyPress == UINT32_MAX);
- REQUIRE(channel0.midiInKeyRel == 1);
- REQUIRE(channel0.midiInKill == 2);
- REQUIRE(channel0.midiInArm == 11);
- REQUIRE(channel0.midiInVolume == 3);
- REQUIRE(channel0.midiInMute == 4);
- REQUIRE(channel0.midiInSolo == 5);
- REQUIRE(channel0.midiOutL == true);
- REQUIRE(channel0.midiOutLplaying == 7);
- REQUIRE(channel0.midiOutLmute == 8);
- REQUIRE(channel0.midiOutLsolo == 9);
- REQUIRE(channel0.samplePath == "/tmp/test.wav");
- REQUIRE(channel0.key == 666);
- REQUIRE(channel0.mode == 0);
- REQUIRE(channel0.begin == 0);
- REQUIRE(channel0.end == 0);
- REQUIRE(channel0.boost == 1.0f);
- REQUIRE(channel0.recActive == 0);
- REQUIRE(channel0.pitch == Approx(1.2f));
- REQUIRE(channel0.midiInReadActions == 0);
- REQUIRE(channel0.midiInPitch == 0);
- REQUIRE(channel0.midiOut == 0);
- REQUIRE(channel0.midiOutChan == 5);
-
- patch::action_t action0 = channel0.actions.at(0);
- REQUIRE(action0.type == 0);
- REQUIRE(action0.frame == 50000);
- REQUIRE(action0.fValue == Approx(0.3f));
- REQUIRE(action0.iValue == 1000);
-
- patch::action_t action1 = channel0.actions.at(1);
- REQUIRE(action1.type == 2);
- REQUIRE(action1.frame == 589);
- REQUIRE(action1.fValue == Approx(1.0f));
- REQUIRE(action1.iValue == 130);
+ REQUIRE(patch::write(filename) == 1);
+ }
+
+ SECTION("test read")
+ {
+ REQUIRE(patch::read(filename) == PATCH_READ_OK);
+ REQUIRE(patch::header == "GPTCH");
+ REQUIRE(patch::version == "1.0");
+ REQUIRE(patch::versionMajor == 6);
+ REQUIRE(patch::versionMinor == 6);
+ REQUIRE(patch::versionPatch == 6);
+ REQUIRE(patch::name == "test patch");
+ REQUIRE(patch::bpm == Approx(100.0f));
+ REQUIRE(patch::bars == 4);
+ REQUIRE(patch::beats == 23);
+ REQUIRE(patch::quantize == 1);
+ REQUIRE(patch::masterVolIn == Approx(1.0f));
+ REQUIRE(patch::masterVolOut == Approx(0.7f));
+ REQUIRE(patch::metronome == 0);
+ REQUIRE(patch::lastTakeId == 0);
+ REQUIRE(patch::samplerate == 44100);
+
+ patch::column_t column0 = patch::columns.at(0);
+ REQUIRE(column0.index == 0);
+ REQUIRE(column0.width == 500);
+
+ patch::channel_t channel0 = patch::channels.at(0);
+ REQUIRE(channel0.type == CHANNEL_SAMPLE);
+ REQUIRE(channel0.index == 666);
+ REQUIRE(channel0.size == G_GUI_CHANNEL_H_1);
+ REQUIRE(channel0.column == 0);
+ REQUIRE(channel0.mute == 0);
+ REQUIRE(channel0.mute_s == 0);
+ REQUIRE(channel0.solo == 0);
+ REQUIRE(channel0.volume == Approx(1.0f));
+ REQUIRE(channel0.pan == Approx(0.5f));
+ REQUIRE(channel0.midiIn == true);
+ REQUIRE(channel0.midiInKeyPress == UINT32_MAX);
+ REQUIRE(channel0.midiInKeyRel == 1);
+ REQUIRE(channel0.midiInKill == 2);
+ REQUIRE(channel0.midiInArm == 11);
+ REQUIRE(channel0.midiInVolume == 3);
+ REQUIRE(channel0.midiInMute == 4);
+ REQUIRE(channel0.midiInSolo == 5);
+ REQUIRE(channel0.midiOutL == true);
+ REQUIRE(channel0.midiOutLplaying == 7);
+ REQUIRE(channel0.midiOutLmute == 8);
+ REQUIRE(channel0.midiOutLsolo == 9);
+ REQUIRE(channel0.samplePath == "/tmp/test.wav");
+ REQUIRE(channel0.key == 666);
+ REQUIRE(channel0.mode == 0);
+ REQUIRE(channel0.begin == 0);
+ REQUIRE(channel0.end == 0);
+ REQUIRE(channel0.boost == 1.0f);
+ REQUIRE(channel0.recActive == 0);
+ REQUIRE(channel0.pitch == Approx(1.2f));
+ REQUIRE(channel0.midiInReadActions == 0);
+ REQUIRE(channel0.midiInPitch == 0);
+ REQUIRE(channel0.midiOut == 0);
+ REQUIRE(channel0.midiOutChan == 5);
+
+ patch::action_t action0 = channel0.actions.at(0);
+ REQUIRE(action0.type == 0);
+ REQUIRE(action0.frame == 50000);
+ REQUIRE(action0.fValue == Approx(0.3f));
+ REQUIRE(action0.iValue == 1000);
+
+ patch::action_t action1 = channel0.actions.at(1);
+ REQUIRE(action1.type == 2);
+ REQUIRE(action1.frame == 589);
+ REQUIRE(action1.fValue == Approx(1.0f));
+ REQUIRE(action1.iValue == 130);
#ifdef WITH_VST
- patch::plugin_t plugin0 = channel0.plugins.at(0);
- REQUIRE(plugin0.path == "/path/to/plugin1");
- REQUIRE(plugin0.bypass == false);
- REQUIRE(plugin0.params.at(0) == Approx(0.0f));
- REQUIRE(plugin0.params.at(1) == Approx(0.1f));
- REQUIRE(plugin0.params.at(2) == Approx(0.2f));
-
- patch::plugin_t plugin1 = channel0.plugins.at(1);
- REQUIRE(plugin1.path == "/another/path/to/plugin2");
- REQUIRE(plugin1.bypass == true);
- REQUIRE(plugin1.params.at(0) == Approx(0.6f));
- REQUIRE(plugin1.params.at(1) == Approx(0.6f));
- REQUIRE(plugin1.params.at(2) == Approx(0.6f));
- REQUIRE(plugin1.params.at(3) == Approx(0.0f));
- REQUIRE(plugin1.params.at(4) == Approx(1.0f));
- REQUIRE(plugin1.params.at(5) == Approx(1.0f));
- REQUIRE(plugin1.params.at(6) == Approx(0.333f));
-
- patch::plugin_t masterPlugin0 = patch::masterInPlugins.at(0);
- REQUIRE(masterPlugin0.path == "/path/to/plugin1");
- REQUIRE(masterPlugin0.bypass == false);
- REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f));
- REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f));
- REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f));
-
- patch::plugin_t masterPlugin1 = patch::masterOutPlugins.at(0);
- REQUIRE(masterPlugin1.path == "/another/path/to/plugin2");
- REQUIRE(masterPlugin1.bypass == true);
- REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f));
- REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f));
- REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f));
- REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f));
- REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f));
- REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f));
- REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f));
+ patch::plugin_t plugin0 = channel0.plugins.at(0);
+ REQUIRE(plugin0.path == "/path/to/plugin1");
+ REQUIRE(plugin0.bypass == false);
+ REQUIRE(plugin0.params.at(0) == Approx(0.0f));
+ REQUIRE(plugin0.params.at(1) == Approx(0.1f));
+ REQUIRE(plugin0.params.at(2) == Approx(0.2f));
+
+ patch::plugin_t plugin1 = channel0.plugins.at(1);
+ REQUIRE(plugin1.path == "/another/path/to/plugin2");
+ REQUIRE(plugin1.bypass == true);
+ REQUIRE(plugin1.params.at(0) == Approx(0.6f));
+ REQUIRE(plugin1.params.at(1) == Approx(0.6f));
+ REQUIRE(plugin1.params.at(2) == Approx(0.6f));
+ REQUIRE(plugin1.params.at(3) == Approx(0.0f));
+ REQUIRE(plugin1.params.at(4) == Approx(1.0f));
+ REQUIRE(plugin1.params.at(5) == Approx(1.0f));
+ REQUIRE(plugin1.params.at(6) == Approx(0.333f));
+
+ patch::plugin_t masterPlugin0 = patch::masterInPlugins.at(0);
+ REQUIRE(masterPlugin0.path == "/path/to/plugin1");
+ REQUIRE(masterPlugin0.bypass == false);
+ REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f));
+ REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f));
+ REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f));
+
+ patch::plugin_t masterPlugin1 = patch::masterOutPlugins.at(0);
+ REQUIRE(masterPlugin1.path == "/another/path/to/plugin2");
+ REQUIRE(masterPlugin1.bypass == true);
+ REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f));
+ REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f));
+ REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f));
+ REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f));
+ REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f));
+ REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f));
+ REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f));
#endif
- }
+ }
}