Browse Source

add ability to change instrument

Partly implements https://todo.sr.ht/~alextee/zrythm-feature/283.
noisegate-plugins
Alexandros Theodotou 2 years ago
parent
commit
0140cc74cf
Signed by: alex
GPG Key ID: 022EAE42313D70F3
  1. 4
      inc/audio/channel.h
  2. 30
      inc/plugins/plugin_identifier.h
  3. 13
      src/actions/mixer_selections_action.c
  4. 12
      src/actions/tracklist_selections.c
  5. 64
      src/audio/channel.c
  6. 8
      src/audio/engine.c
  7. 11
      src/audio/midi_mapping.c
  8. 10
      src/audio/track.c
  9. 4
      src/gui/backend/mixer_selections.c
  10. 34
      src/gui/widgets/channel_slot.c
  11. 4
      src/plugins/plugin.c
  12. 4
      src/plugins/plugin_descriptor.c
  13. 37
      src/plugins/plugin_identifier.c
  14. 1
      subprojects/lilv.wrap
  15. 140
      tests/actions/mixer_selections_action.c

4
inc/audio/channel.h

@ -445,10 +445,10 @@ channel_process (Channel * channel); @@ -445,10 +445,10 @@ channel_process (Channel * channel);
* @param recalc_graph Recalculate mixer graph.
* @param pub_events Publish events.
*
* @return 1 if plugin added, 0 if not.
* @return true if plugin added, false if not.
*/
NONNULL
int
bool
channel_add_plugin (
Channel * channel,
PluginSlotType slot_type,

30
inc/plugins/plugin_identifier.h

@ -79,8 +79,13 @@ typedef struct PluginIdentifier @@ -79,8 +79,13 @@ typedef struct PluginIdentifier
/** The Channel this plugin belongs to. */
int track_pos;
/** The slot this plugin is in in the channel, or
* thie index if this is part of a modulator. */
/**
* The slot this plugin is in in the channel, or
* the index if this is part of a modulator.
*
* If PluginIdentifier.slot_type is an instrument,
* this must be set to -1.
*/
int slot;
} PluginIdentifier;
@ -122,21 +127,24 @@ plugin_identifier_is_equal ( @@ -122,21 +127,24 @@ plugin_identifier_is_equal (
a->slot == b->slot;
}
static inline void
void
plugin_identifier_copy (
PluginIdentifier * dest,
const PluginIdentifier * src)
{
dest->schema_version = src->schema_version;
dest->slot_type = src->slot_type;
dest->track_pos = src->track_pos;
dest->slot = src->slot;
}
const PluginIdentifier * src);
NONNULL
bool
plugin_identifier_validate (
PluginIdentifier * self);
const PluginIdentifier * self);
/**
* Verifies that @ref slot_type and @ref slot is
* a valid combination.
*/
bool
plugin_identifier_validate_slot_type_slot_combo (
PluginSlotType slot_type,
int slot);
static inline void
plugin_identifier_print (

13
src/actions/mixer_selections_action.c

@ -242,7 +242,8 @@ revert_automation ( @@ -242,7 +242,8 @@ revert_automation (
}
/**
* Save an existing plugin about to be replaced.
* Save an existing plugin about to be replaced
* into @ref tmp_ms.
*/
static void
save_existing_plugin (
@ -258,6 +259,16 @@ save_existing_plugin ( @@ -258,6 +259,16 @@ save_existing_plugin (
Plugin * existing_pl =
track_get_plugin_at_slot (
to_tr, to_slot_type, to_slot);
g_debug (
"existing plugin at (%s:%s:%d => %s:%s:%d): %s",
from_tr ? from_tr->name : "(none)",
plugin_slot_type_to_string (from_slot_type),
from_slot,
to_tr ? to_tr->name : "(none)",
plugin_slot_type_to_string (to_slot_type),
to_slot,
existing_pl ?
existing_pl->setting->descr->name : "(none)");
if (existing_pl &&
(from_tr != to_tr ||
from_slot_type != to_slot_type ||

12
src/actions/tracklist_selections.c

@ -483,13 +483,15 @@ create_track ( @@ -483,13 +483,15 @@ create_track (
if (track->channel && pl)
{
bool is_instrument =
track->type == TRACK_TYPE_INSTRUMENT;
channel_add_plugin (
track->channel,
plugin_descriptor_is_instrument (
self->pl_setting->descr) ?
PLUGIN_SLOT_INSTRUMENT :
PLUGIN_SLOT_INSERT,
pl->id.slot, pl,
is_instrument ?
PLUGIN_SLOT_INSTRUMENT :
PLUGIN_SLOT_INSERT,
is_instrument ? -1 : pl->id.slot,
pl,
F_CONFIRM, F_NOT_MOVING_PLUGIN,
F_GEN_AUTOMATABLES, F_NO_RECALC_GRAPH,
F_NO_PUBLISH_EVENTS);

64
src/audio/channel.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2020 Alexandros Theodotou <alex and zrythm dot org>
* Copyright (C) 2018-2021 Alexandros Theodotou <alex and zrythm dot org>
*
* This file is part of Zrythm
*
@ -496,7 +496,7 @@ channel_init_loaded ( @@ -496,7 +496,7 @@ channel_init_loaded (
{
pl = self->instrument;
pl->id.track_pos = self->track_pos;
pl->id.slot = 0;
pl->id.slot = -1;
pl->id.slot_type = PLUGIN_SLOT_INSTRUMENT;
plugin_init_loaded (pl, project);
}
@ -1749,9 +1749,9 @@ channel_remove_plugin ( @@ -1749,9 +1749,9 @@ channel_remove_plugin (
* @param recalc_graph Recalculate mixer graph.
* @param pub_events Publish events.
*
* @return 1 if plugin added, 0 if not.
* @return true if plugin added, false if not.
*/
int
bool
channel_add_plugin (
Channel * self,
PluginSlotType slot_type,
@ -1763,6 +1763,11 @@ channel_add_plugin ( @@ -1763,6 +1763,11 @@ channel_add_plugin (
bool recalc_graph,
bool pub_events)
{
g_return_val_if_fail (
plugin_identifier_validate_slot_type_slot_combo (
slot_type, slot),
false);
int i;
Track * track = channel_get_track (self);
g_return_val_if_fail (
@ -1786,33 +1791,34 @@ channel_add_plugin ( @@ -1786,33 +1791,34 @@ channel_add_plugin (
}
Plugin * existing_pl = NULL;
if (slot_type != PLUGIN_SLOT_INSTRUMENT)
if (slot_type == PLUGIN_SLOT_INSTRUMENT)
existing_pl = self->instrument;
else
existing_pl = plugins[slot];
if (existing_pl)
{
/* confirm if another plugin exists */
existing_pl = plugins[slot];
if (existing_pl)
{
g_message (
"existing plugin exists at %s:%d",
track->name, slot);
}
/* TODO move confirmation to widget */
g_message (
"existing plugin exists at %s:%d",
track->name, slot);
}
/* TODO move confirmation to widget */
#if 0
if (confirm && existing_pl && ZRYTHM_HAVE_UI)
{
GtkDialog * dialog =
dialogs_get_overwrite_plugin_dialog (
GTK_WINDOW (MAIN_WINDOW));
int result =
gtk_dialog_run (dialog);
gtk_widget_destroy (GTK_WIDGET (dialog));
/* do nothing if not accepted */
if (result != GTK_RESPONSE_ACCEPT)
return 0;
}
#endif
/* confirm if another plugin exists */
if (confirm && existing_pl && ZRYTHM_HAVE_UI)
{
GtkDialog * dialog =
dialogs_get_overwrite_plugin_dialog (
GTK_WINDOW (MAIN_WINDOW));
int result =
gtk_dialog_run (dialog);
gtk_widget_destroy (GTK_WIDGET (dialog));
/* do nothing if not accepted */
if (result != GTK_RESPONSE_ACCEPT)
return 0;
}
#endif
/* free current plugin */
if (existing_pl)
@ -2162,7 +2168,7 @@ channel_clone ( @@ -2162,7 +2168,7 @@ channel_clone (
ch->instrument, src_is_project);
channel_add_plugin (
clone, PLUGIN_SLOT_INSTRUMENT,
0, clone_pl, F_NO_CONFIRM,
-1, clone_pl, F_NO_CONFIRM,
F_NOT_MOVING_PLUGIN,
F_GEN_AUTOMATABLES, F_NO_RECALC_GRAPH,
F_NO_PUBLISH_EVENTS);

8
src/audio/engine.c

@ -1403,9 +1403,9 @@ engine_process ( @@ -1403,9 +1403,9 @@ engine_process (
{
if (ZRYTHM_TESTING)
{
g_debug (
"engine process started. total frames to "
"process: %u", total_frames_to_process);
/*g_debug (*/
/*"engine process started. total frames to "*/
/*"process: %u", total_frames_to_process);*/
}
g_return_val_if_fail (
@ -1601,7 +1601,7 @@ engine_process ( @@ -1601,7 +1601,7 @@ engine_process (
if (ZRYTHM_TESTING)
{
g_debug ("engine process ended...");
/*g_debug ("engine process ended...");*/
}
self->last_timestamp_start =

11
src/audio/midi_mapping.c

@ -119,9 +119,14 @@ midi_mappings_bind_at ( @@ -119,9 +119,14 @@ midi_mappings_bind_at (
char str[100];
midi_ctrl_change_get_ch_and_description (
buf, str);
g_message (
"bounded MIDI mapping from %s to %s",
str, dest_port->id.label);
if (!(dest_port->id.flags &
PORT_FLAG_MIDI_AUTOMATABLE))
{
g_message (
"bounded MIDI mapping from %s to %s",
str, dest_port->id.label);
}
if (fire_events && ZRYTHM_HAVE_UI)
{

10
src/audio/track.c

@ -884,6 +884,12 @@ track_validate ( @@ -884,6 +884,12 @@ track_validate (
g_return_val_if_fail (
pid->track_pos == track_pos, false);
Plugin * pl = plugin_find (pid);
g_return_val_if_fail (
plugin_identifier_validate (pid),
false);
g_return_val_if_fail (
plugin_identifier_validate (&pl->id),
false);
g_return_val_if_fail (
plugin_identifier_is_equal (
&pl->id, pid), false);
@ -1885,6 +1891,10 @@ track_insert_plugin ( @@ -1885,6 +1891,10 @@ track_insert_plugin (
bool recalc_graph,
bool fire_events)
{
g_return_if_fail (
plugin_identifier_validate_slot_type_slot_combo (
slot_type, slot));
if (slot_type == PLUGIN_SLOT_MODULATOR)
{
modulator_track_insert_modulator (

4
src/gui/backend/mixer_selections.c

@ -234,6 +234,10 @@ mixer_selections_add_slot ( @@ -234,6 +234,10 @@ mixer_selections_add_slot (
ms->type = type;
ms->has_any = true;
g_debug ("adding slot %s:%s:%d",
track->name,
plugin_slot_type_strings[type].str, slot);
Plugin * pl = NULL;
if (type != PLUGIN_SLOT_INSTRUMENT &&
!array_contains_int (

34
src/gui/widgets/channel_slot.c

@ -73,14 +73,11 @@ get_plugin ( @@ -73,14 +73,11 @@ get_plugin (
break;
case PLUGIN_SLOT_INSTRUMENT:
if (self->track && self->track->channel)
{
return self->track->channel->instrument;
}
return self->track->channel->instrument;
break;
case PLUGIN_SLOT_MODULATOR:
return
self->track->modulators[
self->slot_index];
self->track->modulators[self->slot_index];
break;
default:
g_return_val_if_reached (NULL);
@ -856,8 +853,7 @@ on_drag_motion ( @@ -856,8 +853,7 @@ on_drag_motion (
ChannelSlotWidget * self)
{
GdkModifierType mask;
z_gtk_widget_get_mask (
widget, &mask);
z_gtk_widget_get_mask (widget, &mask);
if (mask & GDK_CONTROL_MASK)
gdk_drag_status (
context, GDK_ACTION_COPY, time);
@ -1019,12 +1015,16 @@ channel_slot_widget_new ( @@ -1019,12 +1015,16 @@ channel_slot_widget_new (
},
};
/* set as drag source for plugin */
gtk_drag_source_set (
GTK_WIDGET (self),
GDK_BUTTON1_MASK,
entries, 1,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
if (type != PLUGIN_SLOT_INSTRUMENT)
{
/* set as drag source for plugin */
gtk_drag_source_set (
GTK_WIDGET (self),
GDK_BUTTON1_MASK,
entries, 1,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
}
/* set as drag dest for both plugins and
* plugin descriptors */
gtk_drag_dest_set (
@ -1046,12 +1046,8 @@ ChannelSlotWidget * @@ -1046,12 +1046,8 @@ ChannelSlotWidget *
channel_slot_widget_new_instrument (void)
{
ChannelSlotWidget * self =
g_object_new (
CHANNEL_SLOT_WIDGET_TYPE, NULL);
self->slot_index = -1;
self->type = PLUGIN_SLOT_INSTRUMENT;
self->track = NULL;
self->open_plugin_inspector_on_click = false;
channel_slot_widget_new (
-1, NULL, PLUGIN_SLOT_INSTRUMENT, false);
return self;
}

4
src/plugins/plugin.c

@ -824,6 +824,10 @@ plugin_set_track_and_slot ( @@ -824,6 +824,10 @@ plugin_set_track_and_slot (
PluginSlotType slot_type,
int slot)
{
g_return_if_fail (
plugin_identifier_validate_slot_type_slot_combo (
slot_type, slot));
pl->id.track_pos = track_pos;
pl->id.slot = slot;
pl->id.slot_type = slot_type;

4
src/plugins/plugin_descriptor.c

@ -376,6 +376,10 @@ plugin_descriptor_is_valid_for_slot_type ( @@ -376,6 +376,10 @@ plugin_descriptor_is_valid_for_slot_type (
case PLUGIN_SLOT_MIDI_FX:
return self->num_midi_outs > 0;
break;
case PLUGIN_SLOT_INSTRUMENT:
return
track_type == TRACK_TYPE_INSTRUMENT &&
plugin_descriptor_is_instrument (self);
default:
break;
}

37
src/plugins/plugin_identifier.c

@ -30,11 +30,46 @@ plugin_identifier_init ( @@ -30,11 +30,46 @@ plugin_identifier_init (
bool
plugin_identifier_validate (
PluginIdentifier * self)
const PluginIdentifier * self)
{
g_return_val_if_fail (
self->schema_version ==
PLUGIN_IDENTIFIER_SCHEMA_VERSION,
false);
g_return_val_if_fail (
plugin_identifier_validate_slot_type_slot_combo (
self->slot_type, self->slot), false);
return true;
}
/**
* Verifies that @ref slot_type and @ref slot is
* a valid combination.
*/
bool
plugin_identifier_validate_slot_type_slot_combo (
PluginSlotType slot_type,
int slot)
{
return
(slot_type == PLUGIN_SLOT_INSTRUMENT &&
slot == -1) ||
(slot_type == PLUGIN_SLOT_INVALID &&
slot == -1) ||
(slot_type != PLUGIN_SLOT_INSTRUMENT &&
slot >= 0);
}
void
plugin_identifier_copy (
PluginIdentifier * dest,
const PluginIdentifier * src)
{
g_return_if_fail (
plugin_identifier_validate (src));
dest->schema_version = src->schema_version;
dest->slot_type = src->slot_type;
dest->track_pos = src->track_pos;
dest->slot = src->slot;
}

1
subprojects/lilv.wrap

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
[wrap-git]
url=https://git.sr.ht/~alextee/z-lilv
revision=zrythm_meson

140
tests/actions/mixer_selections_action.c

@ -1282,6 +1282,143 @@ test_undoing_deletion_of_multiple_inserts (void) @@ -1282,6 +1282,143 @@ test_undoing_deletion_of_multiple_inserts (void)
test_helper_zrythm_cleanup ();
}
static void
_test_replace_instrument (
PluginProtocol prot,
const char * pl_bundle,
const char * pl_uri,
bool with_carla)
{
PluginSetting * setting = NULL;
switch (prot)
{
case PROT_LV2:
setting =
test_plugin_manager_get_plugin_setting (
pl_bundle, pl_uri, with_carla);
g_assert_nonnull (setting);
setting =
plugin_setting_clone (
setting, F_NO_VALIDATE);
break;
case PROT_VST:
#ifdef HAVE_CARLA
{
PluginDescriptor ** descriptors =
z_carla_discovery_create_descriptors_from_file (
pl_bundle, ARCH_64, PROT_VST);
setting =
plugin_setting_new_default (
descriptors[0]);
free (descriptors);
}
#endif
break;
default:
break;
}
/* create an instrument track */
UndoableAction * ua =
tracklist_selections_action_new_create (
TRACK_TYPE_INSTRUMENT, setting, NULL,
TRACKLIST->num_tracks, NULL, 1, -1);
undo_manager_perform (UNDO_MANAGER, ua);
int src_track_pos = TRACKLIST->num_tracks - 1;
Track * src_track =
TRACKLIST->tracks[src_track_pos];
g_assert_true (track_validate (src_track));
/* let the engine run */
g_usleep (1000000);
test_project_save_and_reload ();
src_track =
TRACKLIST->tracks[src_track_pos];
g_assert_true (
IS_PLUGIN_AND_NONNULL (
src_track->channel->instrument));
/* replace the instrument with a new instance */
ua =
mixer_selections_action_new_create (
PLUGIN_SLOT_INSTRUMENT, src_track_pos, -1,
setting, 1);
undo_manager_perform (UNDO_MANAGER, ua);
g_assert_true (track_validate (src_track));
/* duplicate the track */
track_select (
src_track, F_SELECT, true, F_NO_PUBLISH_EVENTS);
ua =
tracklist_selections_action_new_copy (
TRACKLIST_SELECTIONS, TRACKLIST->num_tracks);
g_assert_true (track_validate (src_track));
undo_manager_perform (UNDO_MANAGER, ua);
int dest_track_pos = TRACKLIST->num_tracks - 1;
Track * dest_track =
TRACKLIST->tracks[dest_track_pos];
g_assert_true (
track_validate (src_track));
g_assert_true (
track_validate (dest_track));
undo_manager_undo (UNDO_MANAGER);
undo_manager_undo (UNDO_MANAGER);
undo_manager_undo (UNDO_MANAGER);
undo_manager_redo (UNDO_MANAGER);
undo_manager_redo (UNDO_MANAGER);
undo_manager_redo (UNDO_MANAGER);
g_message ("letting engine run...");
/* let the engine run */
g_usleep (1000000);
test_project_save_and_reload ();
g_message ("done");
plugin_setting_free (setting);
}
static void
test_replace_instrument (void)
{
test_helper_zrythm_init ();
for (int i = 0; i < 2; i++)
{
if (i == 1)
{
#ifdef HAVE_CARLA
#ifdef HAVE_NOIZEMAKER
_test_replace_instrument (
PROT_VST, NOIZEMAKER_PATH, NULL, i);
#endif
#else
break;
#endif
}
#ifdef HAVE_HELM
_test_replace_instrument (
PROT_LV2, HELM_BUNDLE, HELM_URI, i);
#endif
#ifdef HAVE_CARLA_RACK
_test_replace_instrument (
PROT_LV2, CARLA_RACK_BUNDLE, CARLA_RACK_URI,
i);
#endif
}
test_helper_zrythm_cleanup ();
}
int
main (int argc, char *argv[])
{
@ -1289,6 +1426,9 @@ main (int argc, char *argv[]) @@ -1289,6 +1426,9 @@ main (int argc, char *argv[])
#define TEST_PREFIX "/actions/mixer_selections_action/"
g_test_add_func (
TEST_PREFIX "test replace instrument",
(GTestFunc) test_replace_instrument);
g_test_add_func (
TEST_PREFIX
"test undoing deletion of multiple inserts",

Loading…
Cancel
Save