Esempio n. 1
0
static void
bt_edit_application_set_property (GObject * object, guint property_id,
    const GValue * value, GParamSpec * pspec)
{
  BtEditApplication *self = BT_EDIT_APPLICATION (object);
  return_if_disposed ();
  switch (property_id) {
    case EDIT_APPLICATION_SONG:
#ifdef USE_DEBUG
      if (G_OBJECT_REF_COUNT (self->priv->song) != 1) {
        GST_DEBUG ("old song: %" G_OBJECT_REF_COUNT_FMT,
            G_OBJECT_LOG_REF_COUNT (self->priv->song));
      }
#endif
      g_object_try_unref (self->priv->song);
      self->priv->song = BT_SONG (g_value_dup_object (value));
      GST_DEBUG ("new song: %" G_OBJECT_REF_COUNT_FMT,
          G_OBJECT_LOG_REF_COUNT (self->priv->song));
      break;
    case EDIT_APPLICATION_UNSAVED:
      self->priv->unsaved = g_value_get_boolean (value);
      GST_INFO ("set the unsaved flag to %d for the song", self->priv->unsaved);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
  }
}
Esempio n. 2
0
static GObject *
bt_edit_application_constructor (GType type, guint n_construct_params,
    GObjectConstructParam * construct_params)
{
  GObject *object;

  if (G_UNLIKELY (!singleton)) {
    object =
        G_OBJECT_CLASS (bt_edit_application_parent_class)->constructor (type,
        n_construct_params, construct_params);
    singleton = BT_EDIT_APPLICATION (object);
    g_object_add_weak_pointer (object, (gpointer *) (gpointer) & singleton);

    //GST_DEBUG("<<<");
    GST_INFO ("new edit app instantiated");
    // create or ref the shared ui resources
    singleton->priv->ui_resources = bt_ui_resources_new ();

    // create the interaction controller registry
    singleton->priv->ic_registry = btic_registry_new ();
    btic_registry_start_discovery ();

    // create the playback controllers (we need to create them all as they watch
    // the settings them self)
    singleton->priv->pbc_socket = bt_playback_controller_socket_new ();
    singleton->priv->pbc_ic = bt_playback_controller_ic_new ();

    // create the editor change log
    singleton->priv->change_log = bt_change_log_new ();
    g_signal_connect (singleton->priv->change_log, "notify::can-undo",
        G_CALLBACK (on_changelog_can_undo_changed), (gpointer) singleton);
    // create the audio_session
    singleton->priv->audio_session = bt_audio_session_new ();

    // create main window
    GST_INFO ("new edit app created, app: %" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (singleton));
    singleton->priv->main_window = bt_main_window_new ();
    gtk_widget_show_all (GTK_WIDGET (singleton->priv->main_window));
    GST_INFO ("new main_window shown");

    // warning: dereferencing type-punned pointer will break strict-aliasing rules
    g_object_add_weak_pointer (G_OBJECT (singleton->priv->main_window),
        (gpointer *) (gpointer) & singleton->priv->main_window);
    GST_INFO ("new edit app created, app: %" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (singleton));
    //GST_DEBUG(">>>");
  } else {
    object = g_object_ref (singleton);
  }
  return object;
}
Esempio n. 3
0
static void
check_gst_log_handler (GstDebugCategory * category,
    GstDebugLevel level, const gchar * file, const gchar * function, gint line,
    GObject * object, GstDebugMessage * _message, gpointer data)
{
  const gchar *message = gst_debug_message_get (_message);
  gchar *msg, *obj_str;
  const gchar *level_str, *cat_str;
  GstClockTime elapsed;

  //-- check message contents
  if (__check_method && (strstr (function, __check_method) != NULL)
      && __check_test && (strstr (message, __check_test) != NULL))
    __check_error_trapped = TRUE;
  else if (__check_method && (strstr (function, __check_method) != NULL)
      && !__check_test)
    __check_error_trapped = TRUE;
  else if (__check_test && (strstr (message, __check_test) != NULL)
      && !__check_method)
    __check_error_trapped = TRUE;

  if (level > gst_debug_category_get_threshold (category))
    return;

  elapsed =
      GST_CLOCK_DIFF (_priv_bt_info_start_time, gst_util_get_timestamp ());
  level_str = gst_debug_level_get_name (level);
  cat_str = gst_debug_category_get_name (category);
  if (object) {
    if (GST_IS_OBJECT (object)) {
      obj_str = g_strdup_printf ("<%s,%" G_OBJECT_REF_COUNT_FMT ">",
          GST_OBJECT_NAME (object), G_OBJECT_LOG_REF_COUNT (object));
    } else if (GST_IS_OBJECT (object)) {
      obj_str = g_strdup_printf ("<%s,%" G_OBJECT_REF_COUNT_FMT ">",
          G_OBJECT_TYPE_NAME (object), G_OBJECT_LOG_REF_COUNT (object));
    } else {
      obj_str = g_strdup_printf ("%p", object);
    }
  } else {
    obj_str = g_strdup ("");
  }

  msg = g_alloca (95 + strlen (cat_str) + strlen (level_str) + strlen (message)
      + strlen (file) + strlen (function) + strlen (obj_str));
  g_sprintf (msg,
      "%" GST_TIME_FORMAT " %" PID_FMT " %" PTR_FMT " %-7s %20s %s:%d:%s:%s %s",
      GST_TIME_ARGS (elapsed), getpid (), g_thread_self (),
      level_str, cat_str, file, line, function, obj_str, message);
  g_free (obj_str);
  check_print_handler (msg);
}
Esempio n. 4
0
static void
bt_main_pages_init_ui (const BtMainPages * self)
{
  gtk_widget_set_name (GTK_WIDGET (self), "song views");

  GST_INFO ("before creating pages, app: %" G_OBJECT_REF_COUNT_FMT,
      G_OBJECT_LOG_REF_COUNT (self->priv->app));

  // don't emit notify::page for each add
  g_object_freeze_notify ((GObject *) self);

  if (!BT_EDIT_UI_CONFIG ("no-machines-page")) {
    // add wigets for machine view
    self->priv->machines_page = bt_main_page_machines_new (self);
    bt_main_pages_add_tab (self, GTK_WIDGET (self->priv->machines_page),
        _("machines"), "buzztrax_tab_machines",
        _("machines used in the song and their wires"));
  }
  if (!BT_EDIT_UI_CONFIG ("no-patterns-page")) {
    // add wigets for pattern view
    self->priv->patterns_page = bt_main_page_patterns_new (self);
    bt_main_pages_add_tab (self, GTK_WIDGET (self->priv->patterns_page),
        _("patterns"), "buzztrax_tab_patterns", _("event pattern editor"));
  }
  if (!BT_EDIT_UI_CONFIG ("no-sequence-page")) {
    // add wigets for sequence view
    self->priv->sequence_page = bt_main_page_sequence_new (self);
    bt_main_pages_add_tab (self, GTK_WIDGET (self->priv->sequence_page),
        _("sequence"), "buzztrax_tab_sequence", _("song sequence editor"));
  }
  if (!BT_EDIT_UI_CONFIG ("no-wavetable-page")) {
    // add wigets for waves view
    self->priv->waves_page = bt_main_page_waves_new (self);
    bt_main_pages_add_tab (self, GTK_WIDGET (self->priv->waves_page),
        _("wave table"), "buzztrax_tab_waves", _("sample wave table editor"));
  }
  if (!BT_EDIT_UI_CONFIG ("no-info-page")) {
    // add widgets for song info view
    self->priv->info_page = bt_main_page_info_new (self);
    bt_main_pages_add_tab (self, GTK_WIDGET (self->priv->info_page),
        _("information"), "buzztrax_tab_info", _("song meta data editor"));
  }
  // @idea add widgets for machine help view
  // GTK_STOCK_HELP icon
  // embed mozilla/gtk-html/webkit-gtk

  g_object_thaw_notify ((GObject *) self);

  // register event handlers
  g_signal_connect_object (self->priv->app, "notify::song",
      G_CALLBACK (on_song_changed), (gpointer) self, 0);
  g_signal_connect ((gpointer) self, "notify::page",
      G_CALLBACK (on_page_switched), (gpointer) self);

  GST_DEBUG ("  done");
}
Esempio n. 5
0
static void
bt_edit_application_dispose (GObject * object)
{
  BtEditApplication *self = BT_EDIT_APPLICATION (object);

  return_if_disposed ();
  self->priv->dispose_has_run = TRUE;

  /* This should destroy the window as this is a child of the app.
   * Problem 1: On the other hand, this *NEVER* gets called as long as the window keeps its
   * strong reference to the app.
   * Solution 1: Only use weak refs when reffing upstream objects
   */
  GST_DEBUG ("!!!! self=%p", self);

  if (self->priv->song) {
    GST_INFO ("song: %" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (self->priv->song));
    bt_song_stop (self->priv->song);
    g_object_unref (self->priv->song);
    self->priv->song = NULL;
  }

  if (self->priv->main_window) {
    GST_INFO ("main_window: %" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (self->priv->main_window));
    //main-menu.c::on_menu_quit_activate
    gtk_widget_destroy (GTK_WIDGET (self->priv->main_window));
  }

  GST_DEBUG ("  more unrefs");
  g_object_try_unref (self->priv->ui_resources);
  g_object_try_unref (self->priv->pbc_socket);
  g_object_try_unref (self->priv->pbc_ic);
  g_object_try_unref (self->priv->ic_registry);
  g_object_try_unref (self->priv->change_log);
  g_object_try_unref (self->priv->audio_session);

  GST_DEBUG ("  chaining up");
  G_OBJECT_CLASS (bt_edit_application_parent_class)->dispose (object);
  GST_DEBUG ("  done");
}
Esempio n. 6
0
static void
bt_wavetable_dispose (GObject * const object)
{
  const BtWavetable *const self = BT_WAVETABLE (object);
  GList *node;

  return_if_disposed ();
  self->priv->dispose_has_run = TRUE;

  GST_DEBUG ("!!!! self=%p", self);

  g_object_try_weak_unref (self->priv->song);
  // unref list of waves
  if (self->priv->waves) {
    for (node = self->priv->waves; node; node = g_list_next (node)) {
      GST_DEBUG ("  free wave : %" G_OBJECT_REF_COUNT_FMT,
          G_OBJECT_LOG_REF_COUNT (node->data));
      g_object_try_unref (node->data);
      node->data = NULL;
    }
  }

  G_OBJECT_CLASS (bt_wavetable_parent_class)->dispose (object);
}
Esempio n. 7
0
static void
on_song_changed (const BtEditApplication * app, GParamSpec * arg,
    gpointer user_data)
{
  BtMainPageInfo *self = BT_MAIN_PAGE_INFO (user_data);
  BtSong *song;
  GtkTextBuffer *buffer;
  gchar *name, *genre, *author, *create_dts, *change_dts;
  gulong bpm, tpb, bars;
  gchar *info;

  GST_INFO ("song has changed : app=%p, self=%p", app, self);
  g_object_try_unref (self->priv->song_info);

  // get song from app
  g_object_get (self->priv->app, "song", &song, NULL);
  if (!song) {
    self->priv->song_info = NULL;
    return;
  }
  GST_INFO ("song: %" G_OBJECT_REF_COUNT_FMT, G_OBJECT_LOG_REF_COUNT (song));

  g_object_get (song, "song-info", &self->priv->song_info, NULL);
  // update info fields
  g_object_get (self->priv->song_info,
      "name", &name, "genre", &genre, "author", &author, "info", &info,
      "bpm", &bpm, "tpb", &tpb, "bars", &bars,
      "create-dts", &create_dts, "change-dts", &change_dts, NULL);
  g_signal_handlers_block_matched (self->priv->name,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_name_changed,
      (gpointer) self);
  gtk_entry_set_text (self->priv->name, safe_string (name));
  g_free (name);
  g_signal_handlers_unblock_matched (self->priv->name,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_name_changed,
      (gpointer) self);

  g_signal_handlers_block_matched (self->priv->genre,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_genre_changed,
      (gpointer) self);
  gtk_entry_set_text (self->priv->genre, safe_string (genre));
  g_free (genre);
  g_signal_handlers_unblock_matched (self->priv->genre,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_genre_changed,
      (gpointer) self);

  g_signal_handlers_block_matched (self->priv->author,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_author_changed,
      (gpointer) self);
  gtk_entry_set_text (self->priv->author, safe_string (author));
  g_free (author);
  g_signal_handlers_unblock_matched (self->priv->author,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_author_changed,
      (gpointer) self);

  g_signal_handlers_block_matched (self->priv->bpm,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_bpm_changed,
      (gpointer) self);
  gtk_spin_button_set_value (self->priv->bpm, (gdouble) bpm);
  g_signal_handlers_unblock_matched (self->priv->bpm,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_bpm_changed,
      (gpointer) self);

  g_signal_handlers_block_matched (self->priv->tpb,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_tpb_changed,
      (gpointer) self);
  gtk_spin_button_set_value (self->priv->tpb, (gdouble) tpb);
  g_signal_handlers_unblock_matched (self->priv->tpb,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_tpb_changed,
      (gpointer) self);

  g_signal_handlers_block_matched (self->priv->beats,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_beats_changed,
      (gpointer) self);
  gtk_spin_button_set_value (self->priv->beats, (gdouble) (bars / tpb));
  g_signal_handlers_unblock_matched (self->priv->beats,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_beats_changed,
      (gpointer) self);

  /* the iso date is not nice for the user
   * struct tm tm;
   * char dts[255];
   *
   * strptime(create_dts, "%FT%TZ", &tm);
   * strftime(dts, sizeof(buf), "%F %T", &tm);
   *
   * but the code below is simpler and works too :)
   */
  create_dts[10] = ' ';
  create_dts[19] = '\0';
  gtk_entry_set_text (self->priv->date_created, create_dts);
  g_free (create_dts);
  change_dts[10] = ' ';
  change_dts[19] = '\0';
  gtk_entry_set_text (self->priv->date_changed, change_dts);
  g_free (change_dts);

  buffer = gtk_text_view_get_buffer (self->priv->info);
  g_signal_handlers_block_matched (buffer,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_info_changed,
      (gpointer) self);
  gtk_text_buffer_set_text (buffer, safe_string (info), -1);
  g_free (info);
  g_signal_handlers_unblock_matched (buffer,
      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, on_info_changed,
      (gpointer) self);

  g_signal_connect (self->priv->song_info, "notify::name",
      G_CALLBACK (on_name_notify), (gpointer) self);

  // release the references
  g_object_unref (song);
  GST_INFO ("song has changed done");
}
Esempio n. 8
0
/**
 * bt_edit_application_load_song:
 * @self: the application instance to load a new song in
 * @file_name: the song filename to load
 * @err: where to store the error message in case of an error, or %NULL
 *
 * Loads a new song. If there is a previous song instance it will be freed.
 *
 * Returns: true for success
 */
gboolean
bt_edit_application_load_song (const BtEditApplication * self,
    const char *file_name, GError ** err)
{
  gboolean res = FALSE;
  BtSongIO *loader;
  BtSong *song;

  g_return_val_if_fail (BT_IS_EDIT_APPLICATION (self), FALSE);

  GST_INFO ("song name = %s", file_name);

  if ((loader = bt_song_io_from_file (file_name, err))) {
    BtSetup *setup;
    GList *missing_machines, *missing_waves;

    bt_edit_application_ui_lock (self);
    g_signal_connect (loader, "notify::status",
        G_CALLBACK (on_songio_status_changed), (gpointer) self);

    // create new song and release the previous one
    song = bt_song_new (BT_APPLICATION (self));
    g_object_set ((gpointer) self, "song", NULL, NULL);

#ifdef USE_DEBUG
    // do sanity check that bin is empty
    {
      GstBin *bin;
      g_object_get ((gpointer) self, "bin", &bin, NULL);

      if (GST_BIN_NUMCHILDREN (bin)) {
        GList *node = GST_BIN_CHILDREN (bin);
        GST_WARNING ("bin.num_children=%d has left-overs",
            GST_BIN_NUMCHILDREN (bin));

        while (node) {
          GST_WARNING_OBJECT (node->data, "removing object %"
              G_OBJECT_REF_COUNT_FMT, G_OBJECT_LOG_REF_COUNT (node->data));
          gst_bin_remove (bin, GST_ELEMENT (node->data));
          node = GST_BIN_CHILDREN (bin);
        }
      }
      gst_object_unref (bin);
    }
#endif

    // this is synchronous execution
    // https://github.com/Buzztrax/buzztrax/issues/52
    // if we bump glib from 2.32 -> 2.36 we can use GTask and
    // g_task_run_in_thread()
    if (bt_song_io_load (loader, song, err)) {
      BtMachine *machine;

      // get sink-machine
      g_object_get (song, "setup", &setup, NULL);
      if ((machine =
              bt_setup_get_machine_by_type (setup, BT_TYPE_SINK_MACHINE))) {
        if (bt_machine_enable_input_post_level (machine)) {
          // DEBUG
          //bt_song_write_to_highlevel_dot_file(song);
          // DEBUG
          // set new song
          g_object_set ((gpointer) self, "song", song, NULL);
          res = TRUE;
          GST_INFO ("new song activated");
        } else {
          GST_WARNING ("Can't add input level/gain element in sink machine");
        }
        GST_DEBUG ("unreffing stuff after loading");
        g_object_unref (machine);
      } else {
        GST_WARNING ("Can't look up sink machine");
      }
      g_object_unref (setup);
    } else {
      GST_WARNING ("could not load song \"%s\"", file_name);
    }
    self->priv->unsaved = FALSE;
    g_object_notify (G_OBJECT (self), "unsaved");

    bt_edit_application_ui_unlock (self);

    // get missing element info
    bt_child_proxy_get (song, "setup::missing-machines", &missing_machines,
        "wavetable::missing-waves", &missing_waves, NULL);
    // tell about missing machines and/or missing waves
    if (missing_machines || missing_waves) {
      GtkWidget *dialog;

      if ((dialog =
              GTK_WIDGET (bt_missing_song_elements_dialog_new (missing_machines,
                      missing_waves)))) {
        bt_edit_application_attach_child_window (self, GTK_WINDOW (dialog));
        gtk_widget_show_all (dialog);

        gtk_dialog_run (GTK_DIALOG (dialog));
        gtk_widget_destroy (dialog);
      }
    }
    g_object_unref (song);
    g_object_unref (loader);
  } else {
    GST_WARNING ("Unknown extension \"%s\"", file_name);
  }
  return res;
}
Esempio n. 9
0
/**
 * bt_edit_application_new_song:
 * @self: the application instance to create a new song in
 *
 * Creates a new blank song instance. If there is a previous song instance it
 * will be freed.
 *
 * Returns: %TRUE for success
 */
gboolean
bt_edit_application_new_song (const BtEditApplication * self)
{
  gboolean res = FALSE;
  BtSong *song;
  BtSetup *setup;
  BtMachine *machine;
  gchar *id;
  gulong bars;
  GError *err = NULL;

  g_return_val_if_fail (BT_IS_EDIT_APPLICATION (self), FALSE);

  // create new song
  song = bt_song_new (BT_APPLICATION (self));

  bt_child_proxy_get (song, "setup", &setup, "song-info::bars", &bars, NULL);
  // make initial song length 4 timelines
  bt_child_proxy_set (song, "sequence::length", bars * 4, NULL);
  // add audiosink
  id = bt_setup_get_unique_machine_id (setup, "master");
  machine = BT_MACHINE (bt_sink_machine_new (song, id, &err));
  if (err == NULL) {
    GHashTable *properties;

    GST_DEBUG ("sink-machine=%" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (machine));
    g_object_get (machine, "properties", &properties, NULL);
    if (properties) {
      gchar str[G_ASCII_DTOSTR_BUF_SIZE];
      g_hash_table_insert (properties, g_strdup ("xpos"),
          g_strdup (g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, 0.0)));
      g_hash_table_insert (properties, g_strdup ("ypos"),
          g_strdup (g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, 0.0)));
    }
    if (bt_machine_enable_input_post_level (machine)) {
      GST_DEBUG ("sink-machine=%" G_OBJECT_REF_COUNT_FMT,
          G_OBJECT_LOG_REF_COUNT (machine));
      // set new song in application
      g_object_set ((gpointer) self, "song", song, NULL);
      res = TRUE;
    } else {
      GST_WARNING ("Can't add input level/gain element in sink machine");
    }
    GST_DEBUG ("sink-machine=%" G_OBJECT_REF_COUNT_FMT,
        G_OBJECT_LOG_REF_COUNT (machine));
  } else {
    GST_WARNING ("Can't create sink machine: %s", err->message);
    g_error_free (err);
    gst_object_unref (machine);
  }
  g_free (id);

  self->priv->unsaved = FALSE;
  g_object_notify (G_OBJECT (self), "unsaved");

  // release references
  g_object_unref (setup);
  g_object_unref (song);
  return res;
}
Esempio n. 10
0
gint
main (gint argc, gchar ** argv)
{
  gboolean res = FALSE;
  gchar *command = NULL, *input_file_name = NULL;
  BtEditApplication *app;
  GOptionContext *ctx = NULL;
  GOptionGroup *group;
  GError *err = NULL;

#ifdef ENABLE_NLS
  setlocale (LC_ALL, "");
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);
#endif /* ENABLE_NLS */

  bt_setup_for_local_install ();

  GOptionEntry options[] = {
    {"version", '\0', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
        (gpointer) parse_goption_arg, N_("Print application version"), NULL}
    ,
    {"command", 'c', 0, G_OPTION_ARG_STRING, &command, N_("Command name"),
        "{load}"}
    ,
    {"input-file", 'i', 0, G_OPTION_ARG_FILENAME, &input_file_name,
        N_("Input file name"), N_("<songfile>")}
    ,
    {NULL}
  };

  // init libraries
  ctx = g_option_context_new (NULL);
  //g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
  group =
      g_option_group_new ("main", _("buzztrax-edit options"),
      _("Show buzztrax-edit options"), argv[0], NULL);
  g_option_group_add_entries (group, options);
  g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
  g_option_context_set_main_group (ctx, group);

  bt_init_add_option_groups (ctx);
  g_option_context_add_group (ctx, btic_init_get_option_group ());
  g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
  g_option_context_add_group (ctx, clutter_get_option_group_without_init ());
  g_option_context_add_group (ctx, gtk_clutter_get_option_group ());

  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
    g_print ("Error initializing: %s\n", safe_string (err->message));
    g_error_free (err);
    goto Done;
  }

  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "bt-edit", 0,
      "music production environment / editor ui");

  // give some global context info
  g_set_prgname ("buzztrax-edit");
  g_set_application_name ("Buzztrax");
  gtk_window_set_default_icon_name ("buzztrax");
  g_setenv ("PULSE_PROP_media.role", "production", TRUE);

  extern gboolean bt_memory_audio_src_plugin_init (GstPlugin * const plugin);
  gst_plugin_register_static (GST_VERSION_MAJOR,
      GST_VERSION_MINOR,
      "memoryaudiosrc",
      "Plays audio from memory",
      bt_memory_audio_src_plugin_init,
      VERSION, "LGPL", PACKAGE, PACKAGE_NAME, "http://www.buzztrax.org");

  GST_INFO ("starting: thread=%p", g_thread_self ());

  app = bt_edit_application_new ();

  // set a default command, if a file is given
  if (!command && BT_IS_STRING (input_file_name)) {
    command = g_strdup ("l");
  }

  if (command) {
    // depending on the options call the correct method
    if (!strcmp (command, "l") || !strcmp (command, "load")) {
      if (!BT_IS_STRING (input_file_name)) {
        usage (argc, argv, ctx);
        // if commandline options where wrong, just start
        res = bt_edit_application_run (app);
      } else {
        res = bt_edit_application_load_and_run (app, input_file_name);
      }
    } else {
      usage (argc, argv, ctx);
      // if commandline options where wrong, just start
      res = bt_edit_application_run (app);
    }
  } else {
    res = bt_edit_application_run (app);
  }

  // free application
  GST_INFO ("app %" G_OBJECT_REF_COUNT_FMT, G_OBJECT_LOG_REF_COUNT (app));
  g_object_unref (app);

Done:
  g_free (command);
  g_free (input_file_name);
  g_option_context_free (ctx);
  return !res;
}