[easytag/wip/dsf-support: 3/8] Read DSF header information



commit 0db1a474f71ccae24f63f7fe4fa2d246a158bbe8
Author: David King <amigadave amigadave com>
Date:   Sun Nov 9 00:01:55 2014 +0000

    Read DSF header information
    
    https://bugzilla.gnome.org/show_bug.cgi?id=708368

 Makefile.am           |    2 +
 po/POTFILES.in        |    1 +
 src/et_core.c         |   10 ++
 src/et_core.h         |    1 +
 src/tags/dsf_header.c |  252 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/tags/dsf_header.h |   32 ++++++
 6 files changed, 298 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 4c1a261..0fc9d46 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -70,6 +70,7 @@ easytag_SOURCES = \
        src/tags/libapetag/info_mac.c \
        src/tags/libapetag/info_mpc.c \
        src/tags/ape_tag.c \
+       src/tags/dsf_header.c \
        src/tags/flac_header.c \
        src/tags/flac_tag.c \
        src/tags/gio_wrapper.cc \
@@ -122,6 +123,7 @@ easytag_headers = \
        src/tags/libapetag/info_mac.h \
        src/tags/libapetag/info_mpc.h \
        src/tags/ape_tag.h \
+       src/tags/dsf_header.h \
        src/tags/flac_header.h \
        src/tags/flac_tag.h \
        src/tags/gio_wrapper.h \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 195bbf3..4c67fb6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -36,6 +36,7 @@ src/setting.c
 src/status_bar.c
 src/tag_area.c
 src/tags/ape_tag.c
+src/tags/dsf_header.c
 src/tags/flac_header.c
 src/tags/flac_tag.c
 src/tags/id3_tag.c
diff --git a/src/et_core.c b/src/et_core.c
index a07b0f9..fabf16f 100644
--- a/src/et_core.c
+++ b/src/et_core.c
@@ -32,6 +32,7 @@
 #include <errno.h>
 
 #include "application_window.h"
+#include "dsf_header.h"
 #include "easytag.h"
 #include "et_core.h"
 #include "mpeg_header.h"
@@ -110,6 +111,7 @@ const ET_File_Description ETFileDescription[] =
     { MP4_FILE, ".m4p", MP4_TAG}, /* Implemented by Michael Ihde. */
     { MP4_FILE, ".m4v", MP4_TAG},
 #endif
+    { DSF_FILE, ".dsf", UNKNOWN_TAG },
 #ifdef ENABLE_WAVPACK
     { WAVPACK_FILE, ".wv", WAVPACK_TAG}, /* Implemented by Maarten Maathuis. */
 #endif
@@ -659,6 +661,9 @@ GList *ET_Add_File_To_File_List (gchar *filename)
             success = et_mp4_header_read_file_info (file, ETFileInfo, &error);
             break;
 #endif
+        case DSF_FILE:
+            success = et_dsf_header_read_file_info (file, ETFileInfo, &error);
+            break;
 #ifdef ENABLE_OPUS
         case OPUS_FILE:
             success = et_opus_read_file_info (file, ETFileInfo, &error);
@@ -2957,6 +2962,11 @@ ET_Display_File_Data_To_UI (ET_File *ETFile)
             et_mp4_file_header_fields_free (fields);
             break;
 #endif
+        case DSF_FILE:
+            fields = et_dsf_header_display_file_info_to_ui (ETFile);
+            et_application_window_file_area_set_header_fields (window, fields);
+            et_dsf_file_header_fields_free (fields);
+            break;
 #ifdef ENABLE_WAVPACK
         case WAVPACK_FILE:
             fields = et_wavpack_header_display_file_info_to_ui (ETFile);
diff --git a/src/et_core.h b/src/et_core.h
index 3feaecb..785a9aa 100644
--- a/src/et_core.h
+++ b/src/et_core.h
@@ -50,6 +50,7 @@ typedef enum
     OFR_FILE,        // OptimFROG (lossless)      : .ofr .ofs
     WAVPACK_FILE,    // Wavpack (lossless)        : .wv
     OPUS_FILE, /* Ogg Opus File: .opus */
+    DSF_FILE, /* DSD codec in DSF container: .dsf */
     UNKNOWN_FILE
 } ET_File_Type;
 
diff --git a/src/tags/dsf_header.c b/src/tags/dsf_header.c
new file mode 100644
index 0000000..d9f1340
--- /dev/null
+++ b/src/tags/dsf_header.c
@@ -0,0 +1,252 @@
+/* EasyTAG - Tag editor for audio files.
+ * Copyright (C) 2014  David King <amigadave amigadave com>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "dsf_header.h"
+
+#include "easytag.h"
+#include "et_core.h"
+#include "misc.h"
+
+#define DSF_HEADER_LENGTH 80
+#define DSF_HEADER_MAGIC "DSD "
+#define DSF_HEADER_FORMAT_MAGIC "fmt "
+
+/* Read the little-endian 32-bit integer from the next 4 characters. */
+static guint32
+guint32_from_byte (guchar *str)
+{
+    gsize i;
+    guint32 result = 0;
+
+    for (i = 4; i > 0; i--)
+    {
+        result = (result << 8) + str[i - 1];
+    }
+
+    return result;
+}
+
+/* Read the little-endian 64-bit integer from the next 8 characters. */
+static guint64
+guint64_from_byte (guchar *str)
+{
+    gsize i;
+    guint64 result = 0;
+
+    for (i = 8; i > 0; i--)
+    {
+        result = (result << 8) + str[i - 1];
+    }
+
+    return result;
+}
+
+gboolean
+et_dsf_header_read_file_info (GFile *file,
+                              ET_File_Info *ETFileInfo,
+                              GError **error)
+{
+    GFileInputStream *file_istream;
+    GInputStream *istream;
+    guchar header[DSF_HEADER_LENGTH];
+    gsize bytes_read;
+    GFileInfo *info;
+    guint64 file_size_header;
+    goffset file_size;
+    guint32 bps;
+    guint64 n_samples;
+
+    g_return_val_if_fail (file != NULL && ETFileInfo != NULL, FALSE);
+    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+    file_istream = g_file_read (file, NULL, error);
+
+    if (file_istream == NULL)
+    {
+        return FALSE;
+    }
+
+    istream = G_INPUT_STREAM (file_istream);
+
+    /* Read the complete header from the file. */
+    if (!g_input_stream_read_all (istream, &header, DSF_HEADER_LENGTH,
+                                  &bytes_read, NULL, error))
+    {
+        g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %d "
+                 "bytes were read", bytes_read, DSF_HEADER_LENGTH);
+        goto err;
+    }
+
+    info = g_file_input_stream_query_info (file_istream,
+                                           G_FILE_ATTRIBUTE_STANDARD_SIZE,
+                                           NULL, error);
+    g_object_unref (file_istream);
+
+    if (info == NULL)
+    {
+        goto err;
+    }
+
+    file_size = g_file_info_get_size (info);
+    g_object_unref (info);
+
+    if (memcmp (&header, DSF_HEADER_MAGIC, 4) != 0)
+    {
+        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+                     _("Not a DSF file"));
+        goto err;
+    }
+
+    if (memcmp (&header[28], DSF_HEADER_FORMAT_MAGIC, 4) != 0)
+    {
+        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+                     _("Not a DSF file"));
+        goto err;
+    }
+
+    /* 12 (8 bytes) total file size. */
+    file_size_header = guint64_from_byte (&header[12]);
+
+    if (file_size_header != file_size)
+    {
+        g_debug ("DSF file is %" G_GUINT64_FORMAT
+                 " bytes, but the file size stored in the header is %"
+                 G_GOFFSET_FORMAT " bytes", file_size, file_size_header);
+    }
+
+    ETFileInfo->size = file_size;
+    
+    /* 44 (4 bytes) format ID, normally 0. */
+    ETFileInfo->version = guint32_from_byte (&header[44]);
+    
+    /* 48 (4 bytes) channel type, normally 1-7. */
+    ETFileInfo->mode = guint32_from_byte (&header[52]);
+
+    /* 52 (4 bytes) number of channels. */
+
+    /* 56 (4 bytes) sampling frequency, 2822400 or 5644800 Hz. */
+    ETFileInfo->samplerate = guint32_from_byte (&header[56]);
+
+    /* 60 (4 bytes) bits per sample, 1 or 8. */
+    bps = guint32_from_byte (&header[60]);
+
+    /* 64 (8 bytes) sample count (per channel). */
+    n_samples = guint64_from_byte (&header[64]);
+
+    /* 72 (4 bytes) block size per channel, 4096. */
+
+    /* 76 (4 bytes) zero padded. */
+
+    ETFileInfo->duration = n_samples / ETFileInfo->samplerate;
+    ETFileInfo->bitrate = bps * (n_samples / ETFileInfo->duration / 1000);
+
+    return TRUE;
+
+err:
+    g_object_unref (file_istream);
+    return FALSE;
+}
+
+EtFileHeaderFields *
+et_dsf_header_display_file_info_to_ui (const ET_File *ETFile)
+{
+    EtFileHeaderFields *fields;
+    ET_File_Info *info;
+    gchar *time = NULL;
+    gchar *time1 = NULL;
+    gchar *size = NULL;
+    gchar *size1 = NULL;
+
+    info = ETFile->ETFileInfo;
+    fields = g_slice_new (EtFileHeaderFields);
+
+    fields->description = _("DSF File");
+
+    /* Encoder version */
+    fields->version_label = _("Encoder:");
+    fields->version = g_strdup_printf ("%d", info->version);
+
+    /* Bitrate */
+    fields->bitrate = g_strdup_printf (_("%d kb/s"), info->bitrate);
+
+    /* Samplerate */
+    fields->samplerate = g_strdup_printf (_("%d Hz"), info->samplerate);
+
+    /* Mode */
+    fields->mode_label = _("Channels:");
+
+    switch (info->mode)
+    {
+        case 1:
+            fields->mode = g_strdup (_("Mono"));
+            break;
+        case 2:
+            fields->mode = g_strdup (_("Stereo"));
+            break;
+        case 3:
+            fields->mode = g_strdup_printf ("%d", info->mode);
+            break;
+        case 4:
+            fields->mode = g_strdup (_("Quadrophonic"));
+            break;
+        case 5:
+        case 6:
+            fields->mode = g_strdup_printf ("%d", info->mode + 1);
+            break;
+        case 7:
+            fields->mode = g_strdup (_("5.1"));
+            break;
+        default:
+            fields->mode = g_strdup (_("Unknown"));
+            break;
+    }
+
+    /* Size */
+    size = g_format_size (info->size);
+    size1 = g_format_size (ETCore->ETFileDisplayedList_TotalSize);
+    fields->size = g_strdup_printf ("%s (%s)", size, size1);
+    g_free (size);
+    g_free (size1);
+
+    /* Duration */
+    time = Convert_Duration (info->duration);
+    time1 = Convert_Duration (ETCore->ETFileDisplayedList_TotalDuration);
+    fields->duration = g_strdup_printf ("%s (%s)", time, time1);
+    g_free (time);
+    g_free (time1);
+
+    return fields;
+}
+
+void
+et_dsf_file_header_fields_free (EtFileHeaderFields *fields)
+{
+    g_return_if_fail (fields != NULL);
+
+    g_free (fields->version);
+    g_free (fields->bitrate);
+    g_free (fields->samplerate);
+    g_free (fields->mode);
+    g_free (fields->size);
+    g_free (fields->duration);
+    g_slice_free (EtFileHeaderFields, fields);
+}
diff --git a/src/tags/dsf_header.h b/src/tags/dsf_header.h
new file mode 100644
index 0000000..2d2b891
--- /dev/null
+++ b/src/tags/dsf_header.h
@@ -0,0 +1,32 @@
+/* EasyTAG - Tag editor for audio files
+ * Copyright (C) 2014  David King <amigadave amigadave com>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ET_DSF_HEADER_H_
+#define ET_DSF_HEADER_H_
+
+#include "et_core.h"
+
+G_BEGIN_DECLS
+
+gboolean et_dsf_header_read_file_info (GFile *file, ET_File_Info *ETFileInfo, GError **error);
+EtFileHeaderFields * et_dsf_header_display_file_info_to_ui (const ET_File *ETFile);
+void et_dsf_file_header_fields_free (EtFileHeaderFields *fields);
+
+G_END_DECLS
+
+#endif /* ET_DSF_HEADER_H_ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]