Пример #1
0
// load file into non empty song
static void
test_bt_song_io_native_load_twice (BT_TEST_ARGS)
{
  BT_TEST_START;
  GST_INFO ("-- arrange --");
  BtSongIO *song_io =
      bt_song_io_from_file (check_get_test_song_path ("test-simple1.xml"),
      NULL);
  bt_song_io_load (song_io, song, NULL);
  ck_g_object_final_unref (song_io);
  song_io =
      bt_song_io_from_file (check_get_test_song_path ("test-simple2.xml"),
      NULL);

  /* act & assert */
  fail_unless (bt_song_io_load (song_io, song, NULL), NULL);

  GST_INFO ("-- cleanup --");
  ck_g_object_final_unref (song_io);
  BT_TEST_END;
}
Пример #2
0
// load files with errors
static void
test_bt_song_io_native_bad_songs (BT_TEST_ARGS)
{
  BT_TEST_START;
  GST_INFO ("-- arrange --");
  BtSongIO *song_io =
      bt_song_io_from_file (check_get_test_song_path (bad_songs[_i]), NULL);

  GST_INFO ("-- act & assert --");
  GError *err = NULL;
  fail_if (bt_song_io_load (song_io, song, &err), NULL);
  fail_if (err == NULL, NULL);

  GST_INFO ("-- cleanup --");
  g_error_free (err);
  ck_g_object_final_unref (song_io);
  BT_TEST_END;
}
Пример #3
0
/**
 * bt_edit_application_save_song:
 * @self: the application instance to save a song from
 * @file_name: the song filename to save
 * @err: where to store the error message in case of an error, or %NULL
 *
 * Saves a song.
 *
 * Returns: true for success
 */
gboolean
bt_edit_application_save_song (const BtEditApplication * self,
    const char *file_name, GError ** err)
{
  gboolean res = FALSE;
  BtSongIO *saver;

  g_return_val_if_fail (BT_IS_EDIT_APPLICATION (self), FALSE);

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

  if ((saver = bt_song_io_from_file (file_name, err))) {
    gchar *old_file_name = NULL, *bak_file_name = NULL;

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

    // update the time-stamp
    bt_child_proxy_set (self->priv->song, "song-info::change-dts", NULL, NULL);

    bt_child_proxy_get (self->priv->song, "song-info::file-name",
        &old_file_name, NULL);

    /* save file saving (bak files)
     * save
     *   new file (!old_file_name)
     *     chosen file-name already exist
     *       - move to <existing>.bak
     *       - save newfile
     *       - if saving failed, move <existing>.bak back
     *       - if saving worked, delete <existing>.bak
     *     chosen file-name does not exist
     *       - save newfile
     *   existing file
     *     - move to <existing>.bak
     *       - save newfile
     *       - if saving failed, move <existing>.bak back
     * save-as
     *   new file (!old_file_name)
     *     like save of a new-file
     *   existing file
     *     chosen file-name already exist
     *       - like save of an existing file
     *     chosen file-name does not exist
     *       - save newfile
     *
     * - check how other apps do it (check if inodes change if various scenarios)
     * - when loading a file, should we keep the file-handle open, so then when
     *   saving, we can just update it?
     *   - this can help with the wavetable (only updated changed wavetable slots)
     *   - if we can't update it, we can use gsf_input_copy() for external files
     *     (if unchanged)
     * - if the user deletes the file that is currently open -> user error
     */
    if (g_file_test (file_name, G_FILE_TEST_EXISTS)) {
      bak_file_name = g_strconcat (file_name, ".bak", NULL);
      g_rename (file_name, bak_file_name);
    }
    if (bt_song_io_save (saver, self->priv->song, err)) {
      res = TRUE;
      if (!old_file_name || strcmp (old_file_name, file_name)) {
        // saving worked, we remove the bak file as
        // - there was no old_file_name and/or
        // - user has chosen to overwrite this file
        g_unlink (bak_file_name);
      }
    } else {
      GST_WARNING ("could not save song \"%s\"", file_name);
      if (bak_file_name) {
        // saving failed, so move a file we renamed to .bak back
        g_rename (bak_file_name, file_name);
      }
    }
    GST_INFO ("saving done");
    self->priv->unsaved = FALSE;
    g_object_notify (G_OBJECT (self), "unsaved");
    self->priv->need_dts_reset = TRUE;

    bt_edit_application_ui_unlock (self);

    g_free (old_file_name);
    g_free (bak_file_name);
    g_object_unref (saver);
  } else {
    GST_WARNING ("Unknown extension \"%s\"", file_name);
  }
  return res;
}
Пример #4
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;
}