chiark / gitweb /
server/gstdecode.c: Produce the configured sample format directly.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 23 May 2013 02:41:30 +0000 (03:41 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 25 May 2013 13:25:10 +0000 (14:25 +0100)
Introduce a GStreamer resampler, which is benign (and fast) if it has
nothing to do, and set the sink caps to match the configured audio
format.  Hopefully, the normalizer is now trivial.

This means that we must fetch the configuration file, which involves
adding gcrypt to the link.

server/Makefile.am
server/gstdecode.c

index df6f56036131a44f4ce6031510494004c2607a6e..3659187ca505a20450cde1df22366366cfd170a7 100644 (file)
@@ -57,7 +57,7 @@ sbin_PROGRAMS+=disorder-gstdecode
 disorder_gstdecode_SOURCES=gstdecode.c disorder-server.h
 disorder_gstdecode_LDADD=$(LIBOBJS) ../lib/libdisorder.a \
        $(GSTREAMER_PLUGINS_BASE_LIBS) -lgstaudio-0.10 -lgstapp-0.10 \
-       $(GSTREAMER_LIBS)
+       $(GSTREAMER_LIBS) $(LIBGCRYPT)
 disorder_gstdecode_DEPENDENCIES=../lib/libdisorder.a
 endif
 
index 16281080704c454afb63a086efb58a3cfdc351e0..10884a43056076f91973e759e302fd8a4a47fcce 100644 (file)
@@ -76,6 +76,7 @@ static const char *const shapes[] = {
 
 static int dither = -1;
 static int mode = ALBUM;
+static int quality = -1;
 static int shape = -1;
 static gdouble fallback = 0.0;
 
@@ -173,14 +174,14 @@ static void prepare_pipeline(void)
 {
   GstElement *source = gst_element_factory_make("filesrc", "file");
   GstElement *decode = gst_element_factory_make("decodebin", "decode");
+  GstElement *resample = gst_element_factory_make("audioresample",
+                                                  "resample");
   GstElement *convert = gst_element_factory_make("audioconvert", "convert");
   GstElement *sink = gst_element_factory_make("appsink", "sink");
   GstElement *tail = sink;
   GstElement *gain;
-  GstCaps *caps = gst_caps_new_empty();
-  GstCaps *c;
-  static const int widths[] = { 8, 16 };
-  size_t i;
+  GstCaps *caps;
+  const struct stream_header *fmt = &config->sample_format;
 
   /* Set up the global variables. */
   pipeline = gst_pipeline_new("pipe");
@@ -190,34 +191,38 @@ static void prepare_pipeline(void)
   g_object_set(source, "location", file, END);
   g_object_set(sink, "sync", FALSE, END);
 
-  /* Configure the converter.  Leave things as their defaults if the user
-   * hasn't made an explicit request.
+  /* Configure the resampler and converter.  Leave things as their defaults
+   * if the user hasn't made an explicit request.
    */
+  if(quality >= 0) g_object_set(resample, "quality", quality, END);
   if(dither >= 0) g_object_set(convert, "dithering", dither, END);
   if(shape >= 0) g_object_set(convert, "noise-shaping", shape, END);
 
-  /* Set up the sink's capabilities. */
-  for(i = 0; i < N(widths); i++) {
-    c = gst_caps_new_simple("audio/x-raw-int",
-                            "width", G_TYPE_INT, widths[i],
-                            "depth", G_TYPE_INT, widths[i],
-                            "channels", GST_TYPE_INT_RANGE, 1, 2,
-                            "signed", G_TYPE_BOOLEAN, TRUE,
-                            "rate", GST_TYPE_INT_RANGE, 100, 1000000,
-                            END);
-    gst_caps_append(caps, c);
-  }
+  /* Set up the sink's capabilities from the configuration. */
+  caps = gst_caps_new_simple("audio/x-raw-int",
+                             "width", G_TYPE_INT, fmt->bits,
+                             "depth", G_TYPE_INT, fmt->bits,
+                             "channels", G_TYPE_INT, fmt->channels,
+                             "signed", G_TYPE_BOOLEAN, TRUE,
+                             "rate", G_TYPE_INT, fmt->rate,
+                             "endianness", G_TYPE_INT,
+                               fmt->endian == ENDIAN_BIG ?
+                                 G_BIG_ENDIAN : G_LITTLE_ENDIAN,
+                             END);
   gst_app_sink_set_caps(appsink, caps);
 
   /* Add the various elements into the pipeline.  We'll stitch them together
    * in pieces, because the pipeline is somewhat dynamic.
    */
-  gst_bin_add_many(GST_BIN(pipeline), source, decode, convert, sink, END);
+  gst_bin_add_many(GST_BIN(pipeline),
+                   source, decode,
+                   resample, convert, sink, END);
 
-  /* Link an audio conversion stage onto the front.  The rest of DisOrder
+  /* Link audio conversion stages onto the front.  The rest of DisOrder
    * doesn't handle much of the full panoply of exciting audio formats.
    */
   link_elements(convert, tail); tail = convert;
+  link_elements(resample, tail); tail = resample;
 
   /* If we're meant to do ReplayGain then insert it into the pipeline before
    * the converter.
@@ -393,12 +398,26 @@ static double getfloat(const char *what, const char *s)
   return d;
 }
 
+static int getint(const char *what, const char *s, int min, int max)
+{
+  long i;
+  char *q;
+
+  errno = 0;
+  i = strtol(s, &q, 10);
+  if(*q || errno || min > i || i > max)
+    disorder_fatal(0, "invalid %s `%s'", what, s);
+  return (int)i;
+}
+
 static const struct option options[] = {
   { "help", no_argument, 0, 'h' },
   { "version", no_argument, 0, 'V' },
+  { "config", required_argument, 0, 'c' },
   { "dither", required_argument, 0, 'd' },
   { "fallback-gain", required_argument, 0, 'f' },
   { "noise-shape", required_argument, 0, 'n' },
+  { "quality", required_argument, 0, 'q' },
   { "replay-gain", required_argument, 0, 'r' },
   { 0, 0, 0, 0 }
 };
@@ -410,11 +429,13 @@ static void help(void)
           "Options:\n"
           "  --help, -h                 Display usage message\n"
           "  --version, -V              Display version number\n"
+          "  --config PATH, -c PATH     Set configuration file\n"
           "  --dither TYPE, -d TYPE     TYPE is `none', `rpdf', `tpdf', or "
                                                 "`tpdf-hf'\n"
           "  --fallback-gain DB, -f DB  For tracks without ReplayGain data\n"
           "  --noise-shape TYPE, -n TYPE  TYPE is `none', `error-feedback',\n"
           "                                     `simple', `medium' or `high'\n"
+          "  --quality QUAL, -q QUAL    Resampling quality: 0 poor, 10 good\n"
           "  --replay-gain MODE, -r MODE  MODE is `off', `track' or `album'\n"
           "\n"
           "Alternative audio decoder for DisOrder.  Only intended to be\n"
@@ -434,13 +455,15 @@ int main(int argc, char *argv[])
   if(!setlocale(LC_CTYPE, "")) disorder_fatal(errno, "calling setlocale");
 
   /* Parse command line. */
-  while((n = getopt_long(argc, argv, "hVd:f:n:r:", options, 0)) >= 0) {
+  while((n = getopt_long(argc, argv, "hVc:d:f:n:q:r:", options, 0)) >= 0) {
     switch(n) {
     case 'h': help();
     case 'V': version("disorder-gstdecode");
+    case 'c': configfile = optarg; break;
     case 'd': dither = getenum("dither type", optarg, dithers); break;
     case 'f': fallback = getfloat("fallback gain", optarg); break;
     case 'n': shape = getenum("noise-shaping type", optarg, shapes); break;
+    case 'q': quality = getint("resample quality", optarg, 0, 10); break;
     case 'r': mode = getenum("ReplayGain mode", optarg, modes); break;
     default: disorder_fatal(0, "invalid option");
     }
@@ -448,6 +471,7 @@ int main(int argc, char *argv[])
   if(optind >= argc) disorder_fatal(0, "missing filename");
   file = argv[optind++];
   if(optind < argc) disorder_fatal(0, "excess arguments");
+  if(config_read(1, 0)) disorder_fatal(0, "cannot read configuration");
 
   /* Set up the GStreamer machinery. */
   gst_init(0, 0);