changeset 1305:51bf0e431e02

Add SHNplug.
author William Pitcock <nenolod@atheme-project.org>
date Fri, 20 Jul 2007 10:29:54 -0500
parents c198ae31bb74
children cbccccf7ea84
files src/shnplug/Makefile src/shnplug/array.c src/shnplug/bitshift.h src/shnplug/convert.c src/shnplug/fixio.c src/shnplug/gtk.c src/shnplug/id3v2.c src/shnplug/misc.c src/shnplug/output.c src/shnplug/seek.c src/shnplug/shn.c src/shnplug/shn.h src/shnplug/shorten.c src/shnplug/shorten.h src/shnplug/sulawalaw.c src/shnplug/vario.c src/shnplug/wave.c
diffstat 17 files changed, 4486 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/Makefile	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,30 @@
+include ../../mk/rules.mk
+include ../../mk/init.mk
+
+OBJECTIVE_LIBS = libshnplug$(SHARED_SUFFIX)
+
+LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR)
+
+SOURCES = \
+  array.c \
+  convert.c \
+  fixio.c \
+  gtk.c \
+  id3v2.c \
+  misc.c \
+  output.c \
+  seek.c \
+  shn.c \
+  shorten.c \
+  sulawalaw.c \
+  vario.c \
+  wave.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+CFLAGS   += $(PICFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) $(ARCH_DEFINES) $(SIMD_CFLAGS) -I../../intl -I../.. -Wall
+
+LDFLAGS += $(AUDLDFLAGS)
+LIBADD = -L/opt/local/lib -L$(plugindir) -Wl,-rpath=$(plugindir) -laudid3tag $(GTK_LIBS) $(GLIB_LIBS) $(PANGO_LIBS)
+
+include ../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/array.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,40 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright (C) 1992-1995 Tony Robinson                                      *
+*                                                                             *
+*  See the file doc/LICENSE.shorten for conditions on distribution and usage  *
+*                                                                             *
+******************************************************************************/
+
+/*
+ * $Id: array.c,v 1.7 2003/08/26 05:34:04 jason Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "shorten.h"
+
+void *pmalloc(ulong size, shn_file *this_shn) {
+  void *ptr;
+
+  ptr = malloc(size);
+
+  if(ptr == NULL)
+    shn_error_fatal(this_shn,"Call to malloc(%ld) failed in pmalloc() -\nyour system may be low on memory", size);
+
+  return(ptr);
+}
+
+slong **long2d(ulong n0, ulong n1, shn_file *this_shn) {
+  slong **array0 = NULL;
+
+  if((array0 = (slong**) pmalloc((ulong) (n0 * sizeof(slong*) +
+					 n0 * n1 * sizeof(slong)),this_shn)) != NULL ) {
+    slong *array1 = (slong*) (array0 + n0);
+    int i;
+
+    for(i = 0; i < n0; i++)
+      array0[i] = array1 + i * n1;
+  }
+  return(array0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/bitshift.h	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,33 @@
+char ulaw_maxshift[256] = {12,8,7,9,7,8,7,10,7,8,7,9,7,8,7,11,6,7,6,8,6,7,6,9,6,7,6,8,6,7,6,10,5,6,5,7,5,6,5,8,5,6,5,7,5,6,5,9,5,4,6,4,5,4,7,4,5,4,6,4,5,4,8,4,3,5,3,4,3,6,3,4,3,5,3,4,3,7,3,4,2,3,2,5,2,3,2,4,2,3,2,6,2,3,2,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,0,7,8,7,9,7,8,7,10,7,8,7,9,7,8,7,11,6,7,6,8,6,7,6,9,6,7,6,8,6,7,6,10,5,6,5,7,5,6,5,8,5,6,5,7,5,6,5,9,5,4,6,4,5,4,7,4,5,4,6,4,5,4,8,4,3,5,3,4,3,6,3,4,3,5,3,4,3,7,3,4,2,3,2,5,2,3,2,4,2,3,2,6,2,3,2,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,12};
+
+schar ulaw_inward[13][256] = {
+{-127,-126,-125,-124,-123,-122,-121,-120,-119,-118,-117,-116,-115,-114,-113,-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,-128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0},
+{-119,-118,-117,-116,-115,-114,-113,-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-128,-7,-127,-6,-126,-5,-125,-4,-124,-3,-123,-2,-122,-1,-121,-120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,127,7,126,6,125,5,124,4,123,3,122,2,121,1,120,0},
+{-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-128,-11,-127,-10,-126,-9,-125,-8,-124,-7,-123,-6,-122,-5,-121,-4,-120,-119,-118,-3,-117,-116,-115,-2,-114,-113,-112,-1,-111,-110,-109,-108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,127,11,126,10,125,9,124,8,123,7,122,6,121,5,120,4,119,118,117,3,116,115,114,2,113,112,111,1,110,109,108,0},
+{-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-128,-13,-127,-12,-126,-11,-125,-10,-124,-9,-123,-8,-122,-7,-121,-6,-120,-119,-118,-5,-117,-116,-115,-4,-114,-113,-112,-3,-111,-110,-109,-2,-108,-107,-106,-105,-104,-103,-102,-1,-101,-100,-99,-98,-97,-96,-95,-94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,127,13,126,12,125,11,124,10,123,9,122,8,121,7,120,6,119,118,117,5,116,115,114,4,113,112,111,3,110,109,108,2,107,106,105,104,103,102,101,1,100,99,98,97,96,95,94,0},
+{-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-128,-14,-127,-13,-126,-12,-125,-11,-124,-10,-123,-9,-122,-8,-121,-7,-120,-119,-118,-6,-117,-116,-115,-5,-114,-113,-112,-4,-111,-110,-109,-3,-108,-107,-106,-105,-104,-103,-102,-2,-101,-100,-99,-98,-97,-96,-95,-1,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,127,14,126,13,125,12,124,11,123,10,122,9,121,8,120,7,119,118,117,6,116,115,114,5,113,112,111,4,110,109,108,3,107,106,105,104,103,102,101,2,100,99,98,97,96,95,94,1,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,0},
+{-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-128,-14,-127,-13,-126,-12,-125,-11,-124,-10,-123,-9,-122,-8,-121,-120,-7,-119,-118,-117,-6,-116,-115,-114,-5,-113,-112,-111,-4,-110,-109,-108,-107,-106,-3,-105,-104,-103,-102,-101,-100,-99,-2,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-1,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,127,14,126,13,125,12,124,11,123,10,122,9,121,8,120,119,7,118,117,116,6,115,114,113,5,112,111,110,4,109,108,107,106,105,3,104,103,102,101,100,99,98,2,97,96,95,94,93,92,91,90,89,88,87,1,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,0},
+{-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-128,-15,-127,-14,-126,-13,-125,-12,-124,-11,-123,-10,-122,-9,-121,-8,-120,-119,-7,-118,-117,-116,-6,-115,-114,-113,-5,-112,-111,-110,-4,-109,-108,-107,-106,-105,-104,-3,-103,-102,-101,-100,-99,-98,-97,-2,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-1,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,127,15,126,14,125,13,124,12,123,11,122,10,121,9,120,8,119,118,7,117,116,115,6,114,113,112,5,111,110,109,4,108,107,106,105,104,103,3,102,101,100,99,98,97,96,2,95,94,93,92,91,90,89,88,87,86,85,84,83,1,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,0},
+{-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-128,-15,-127,-14,-126,-13,-125,-12,-124,-11,-123,-10,-122,-9,-121,-8,-120,-119,-118,-7,-117,-116,-115,-6,-114,-113,-112,-5,-111,-110,-109,-4,-108,-107,-106,-105,-104,-103,-3,-102,-101,-100,-99,-98,-97,-96,-2,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-1,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,127,15,126,14,125,13,124,12,123,11,122,10,121,9,120,8,119,118,117,7,116,115,114,6,113,112,111,5,110,109,108,4,107,106,105,104,103,102,3,101,100,99,98,97,96,95,2,94,93,92,91,90,89,88,87,86,85,84,83,82,81,1,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,0},
+{-16,-15,-128,-14,-127,-13,-126,-12,-125,-11,-124,-10,-123,-9,-122,-8,-121,-120,-119,-7,-118,-117,-116,-6,-115,-114,-113,-5,-112,-111,-110,-4,-109,-108,-107,-106,-105,-104,-103,-3,-102,-101,-100,-99,-98,-97,-96,-2,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-1,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,127,15,126,14,125,13,124,12,123,11,122,10,121,9,120,8,119,118,117,7,116,115,114,6,113,112,111,5,110,109,108,4,107,106,105,104,103,102,101,3,100,99,98,97,96,95,94,2,93,92,91,90,89,88,87,86,85,84,83,82,81,80,1,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,0},
+{-8,-128,-127,-7,-126,-125,-124,-6,-123,-122,-121,-5,-120,-119,-118,-4,-117,-116,-115,-114,-113,-112,-111,-3,-110,-109,-108,-107,-106,-105,-104,-2,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-1,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,127,126,125,7,124,123,122,6,121,120,119,5,118,117,116,4,115,114,113,112,111,110,109,3,108,107,106,105,104,103,102,2,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,1,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,0},
+{-4,-128,-127,-126,-125,-124,-123,-3,-122,-121,-120,-119,-118,-117,-116,-2,-115,-114,-113,-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101,-1,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,127,126,125,124,123,122,121,3,120,119,118,117,116,115,114,2,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,1,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,0},
+{-2,-128,-127,-126,-125,-124,-123,-122,-121,-120,-119,-118,-117,-116,-115,-1,-114,-113,-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,1,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,0},
+{-1,-128,-127,-126,-125,-124,-123,-122,-121,-120,-119,-118,-117,-116,-115,-114,-113,-112,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,-77,-76,-75,-74,-73,-72,-71,-70,-69,-68,-67,-66,-65,-64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}
+};
+
+uchar ulaw_outward[13][256] = {
+{127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128},
+{112,114,116,118,120,122,124,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,113,115,117,119,121,123,125,255,253,251,249,247,245,243,241,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,252,250,248,246,244,242,240},
+{96,98,100,102,104,106,108,110,112,113,114,116,117,118,120,121,122,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,97,99,101,103,105,107,109,111,115,119,123,255,251,247,243,239,237,235,233,231,229,227,225,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,250,249,248,246,245,244,242,241,240,238,236,234,232,230,228,226,224},
+{80,82,84,86,88,90,92,94,96,97,98,100,101,102,104,105,106,108,109,110,112,113,114,115,116,117,118,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,81,83,85,87,89,91,93,95,99,103,107,111,119,255,247,239,235,231,227,223,221,219,217,215,213,211,209,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,246,245,244,243,242,241,240,238,237,236,234,233,232,230,229,228,226,225,224,222,220,218,216,214,212,210,208},
+{64,66,68,70,72,74,76,78,80,81,82,84,85,86,88,89,90,92,93,94,96,97,98,99,100,101,102,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,65,67,69,71,73,75,77,79,83,87,91,95,103,111,255,239,231,223,219,215,211,207,205,203,201,199,197,195,193,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,238,237,236,235,234,233,232,230,229,228,227,226,225,224,222,221,220,218,217,216,214,213,212,210,209,208,206,204,202,200,198,196,194,192},
+{49,51,53,55,57,59,61,63,64,66,67,68,70,71,72,74,75,76,78,79,80,81,82,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,52,54,56,58,60,62,65,69,73,77,83,91,103,255,231,219,211,205,201,197,193,190,188,186,184,182,180,178,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,230,229,228,227,226,225,224,223,222,221,220,218,217,216,215,214,213,212,210,209,208,207,206,204,203,202,200,199,198,196,195,194,192,191,189,187,185,183,181,179,177},
+{32,34,36,38,40,42,44,46,48,49,51,52,53,55,56,57,59,60,61,63,64,65,66,67,68,70,71,72,73,74,75,76,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,35,37,39,41,43,45,47,50,54,58,62,69,77,91,255,219,205,197,190,186,182,178,175,173,171,169,167,165,163,161,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,218,217,216,215,214,213,212,211,210,209,208,207,206,204,203,202,201,200,199,198,196,195,194,193,192,191,189,188,187,185,184,183,181,180,179,177,176,174,172,170,168,166,164,162,160},
+{16,18,20,22,24,26,28,30,32,33,34,36,37,38,40,41,42,44,45,46,48,49,50,51,52,53,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70,71,72,73,74,75,76,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,29,31,35,39,43,47,54,62,77,255,205,190,182,175,171,167,163,159,157,155,153,151,149,147,145,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,204,203,202,201,200,199,198,197,196,195,194,193,192,191,189,188,187,186,185,184,183,181,180,179,178,177,176,174,173,172,170,169,168,166,165,164,162,161,160,158,156,154,152,150,148,146,144},
+{2,4,6,8,10,12,14,16,17,18,20,21,22,24,25,26,28,29,30,32,33,34,35,36,37,38,40,41,42,43,44,45,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,3,5,7,9,11,13,15,19,23,27,31,39,47,62,255,190,175,167,159,155,151,147,143,141,139,137,135,133,131,129,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,189,188,187,186,185,184,183,182,181,180,179,178,177,176,174,173,172,171,170,169,168,166,165,164,163,162,161,160,158,157,156,154,153,152,150,149,148,146,145,144,142,140,138,136,134,132,130,128},
+{1,2,4,5,6,8,9,10,12,13,14,16,17,18,19,20,21,22,24,25,26,27,28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,3,7,11,15,23,31,47,255,175,159,151,143,139,135,131,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,158,157,156,155,154,153,152,150,149,148,147,146,145,144,142,141,140,138,137,136,134,133,132,130,129,128},
+{1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,7,15,31,255,159,143,135,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,142,141,140,139,138,137,136,134,133,132,131,130,129,128},
+{1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,15,255,143,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128},
+{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/convert.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,42 @@
+/*  convert.c - functions to convert little-endian data to endian of host
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: convert.c,v 1.9 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdlib.h>
+#include "shorten.h"
+
+ulong shn_uchar_to_ulong_le(uchar *buf)
+/* converts 4 bytes stored in little-endian format to a ulong */
+{
+	return (ulong)((buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]);
+}
+
+slong shn_uchar_to_slong_le(uchar *buf)
+/* converts 4 bytes stored in little-endian format to an slong */
+{
+	return (slong)shn_uchar_to_ulong_le(buf);
+}
+
+ushort shn_uchar_to_ushort_le(uchar *buf)
+/* converts 4 bytes stored in little-endian format to a ushort */
+{
+	return (ushort)((buf[1] << 8) + buf[0]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/fixio.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,279 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright (C) 1992-1995 Tony Robinson                                      *
+*                                                                             *
+*  See the file doc/LICENSE.shorten for conditions on distribution and usage  *
+*                                                                             *
+******************************************************************************/
+
+/*
+ * $Id: fixio.c,v 1.7 2003/08/26 05:34:04 jason Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "shorten.h"
+#include "bitshift.h"
+
+void swab(const void *from, void *to, ssize_t n);
+
+#define CAPMAXSCHAR(x)  ((x > 127) ? 127 : x)
+#define CAPMAXUCHAR(x)  ((x > 255) ? 255 : x)
+#define CAPMAXSHORT(x)  ((x > 32767) ? 32767 : x)
+#define CAPMAXUSHORT(x) ((x > 65535) ? 65535 : x)
+
+static int sizeof_sample[TYPE_EOF];
+
+void init_sizeof_sample() {
+  sizeof_sample[TYPE_AU1]   = sizeof(uchar);
+  sizeof_sample[TYPE_S8]    = sizeof(schar);
+  sizeof_sample[TYPE_U8]    = sizeof(uchar);
+  sizeof_sample[TYPE_S16HL] = sizeof(ushort);
+  sizeof_sample[TYPE_U16HL] = sizeof(ushort);
+  sizeof_sample[TYPE_S16LH] = sizeof(ushort);
+  sizeof_sample[TYPE_U16LH] = sizeof(ushort);
+  sizeof_sample[TYPE_ULAW]  = sizeof(uchar);
+  sizeof_sample[TYPE_AU2]   = sizeof(uchar);
+  sizeof_sample[TYPE_AU3]   = sizeof(uchar);
+  sizeof_sample[TYPE_ALAW]  = sizeof(uchar);
+}
+
+/***************/
+/* fixed write */
+/***************/
+
+void fwrite_type_init(shn_file *this_shn) {
+  init_sizeof_sample();
+  this_shn->decode_state->writebuf  = (schar*) NULL;
+  this_shn->decode_state->writefub  = (schar*) NULL;
+  this_shn->decode_state->nwritebuf = 0;
+}
+
+void fwrite_type_quit(shn_file *this_shn) {
+  if(this_shn->decode_state->writebuf != NULL) {
+    free(this_shn->decode_state->writebuf);
+    this_shn->decode_state->writebuf = NULL;
+  }
+  if(this_shn->decode_state->writefub != NULL) {
+    free(this_shn->decode_state->writefub);
+    this_shn->decode_state->writefub = NULL;
+  }
+}
+
+/* convert from signed ints to a given type and write */
+void fwrite_type(slong **data,int ftype,int nchan,int nitem,shn_file *this_shn)
+{
+  int hiloint = 1, hilo = !(*((char*) &hiloint));
+  int i, nwrite = 0, datasize = sizeof_sample[ftype], chan;
+  slong *data0 = data[0];
+  int bufAvailable = OUT_BUFFER_SIZE - this_shn->vars.bytes_in_buf;
+
+  if(this_shn->decode_state->nwritebuf < nchan * nitem * datasize) {
+    this_shn->decode_state->nwritebuf = nchan * nitem * datasize;
+    if(this_shn->decode_state->writebuf != NULL) free(this_shn->decode_state->writebuf);
+    if(this_shn->decode_state->writefub != NULL) free(this_shn->decode_state->writefub);
+    this_shn->decode_state->writebuf = (schar*) pmalloc((ulong) this_shn->decode_state->nwritebuf,this_shn);
+    if (!this_shn->decode_state->writebuf)
+      return;
+    this_shn->decode_state->writefub = (schar*) pmalloc((ulong) this_shn->decode_state->nwritebuf,this_shn);
+    if (!this_shn->decode_state->writefub)
+      return;
+  }
+
+  switch(ftype) {
+  case TYPE_AU1: /* leave the conversion to fix_bitshift() */
+  case TYPE_AU2: {
+    uchar *writebufp = (uchar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = data0[i];
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = data[chan][i];
+    break;
+  }
+  case TYPE_U8: {
+    uchar *writebufp = (uchar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = CAPMAXUCHAR(data0[i]);
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ =  CAPMAXUCHAR(data[chan][i]);
+    break;
+  }
+  case TYPE_S8: {
+    schar *writebufp = (schar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = CAPMAXSCHAR(data0[i]);
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = CAPMAXSCHAR(data[chan][i]);
+    break;
+  }
+  case TYPE_S16HL:
+  case TYPE_S16LH: {
+    short *writebufp = (short*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = CAPMAXSHORT(data0[i]);
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = CAPMAXSHORT(data[chan][i]);
+    break;
+  }
+  case TYPE_U16HL:
+  case TYPE_U16LH: {
+    ushort *writebufp = (ushort*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = CAPMAXUSHORT(data0[i]);
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = CAPMAXUSHORT(data[chan][i]);
+    break;
+  }
+  case TYPE_ULAW: {
+    uchar *writebufp = (uchar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = Slinear2ulaw(CAPMAXSHORT((data0[i] << 3)));
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = Slinear2ulaw(CAPMAXSHORT((data[chan][i] << 3)));
+    break;
+  }
+  case TYPE_AU3: {
+    uchar *writebufp = (uchar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	if(data0[i] < 0)
+	  *writebufp++ = (127 - data0[i]) ^ 0xd5;
+	else
+	  *writebufp++ = (data0[i] + 128) ^ 0x55;
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  if(data[chan][i] < 0)
+	    *writebufp++ = (127 - data[chan][i]) ^ 0xd5;
+	  else
+	    *writebufp++ = (data[chan][i] + 128) ^ 0x55;
+    break;
+  }
+  case TYPE_ALAW: {
+    uchar *writebufp = (uchar*) this_shn->decode_state->writebuf;
+    if(nchan == 1)
+      for(i = 0; i < nitem; i++)
+	*writebufp++ = Slinear2alaw(CAPMAXSHORT((data0[i] << 3)));
+    else
+      for(i = 0; i < nitem; i++)
+	for(chan = 0; chan < nchan; chan++)
+	  *writebufp++ = Slinear2alaw(CAPMAXSHORT((data[chan][i] << 3)));
+    break;
+  }
+  }
+
+  switch(ftype) {
+  case TYPE_AU1:
+  case TYPE_S8:
+  case TYPE_U8:
+  case TYPE_ULAW:
+  case TYPE_AU2:
+  case TYPE_AU3:
+  case TYPE_ALAW:
+    if (datasize*nchan*nitem <= bufAvailable) {
+      memcpy((void *)&this_shn->vars.buffer[this_shn->vars.bytes_in_buf],(const void *)this_shn->decode_state->writebuf,datasize*nchan*nitem);
+      this_shn->vars.bytes_in_buf += datasize*nchan*nitem;
+      nwrite = nitem;
+    }
+    else
+      shn_debug("Buffer overrun in fwrite_type() [case 1]: %d bytes to read, but only %d bytes are available",datasize*nchan*nitem,bufAvailable);
+    break;
+  case TYPE_S16HL:
+  case TYPE_U16HL:
+    if(hilo)
+    {
+      if (datasize*nchan*nitem <= bufAvailable) {
+        memcpy((void *)&this_shn->vars.buffer[this_shn->vars.bytes_in_buf],(const void *)this_shn->decode_state->writebuf,datasize*nchan*nitem);
+        this_shn->vars.bytes_in_buf += datasize*nchan*nitem;
+        nwrite = nitem;
+      }
+      else
+        shn_debug("Buffer overrun in fwrite_type() [case 2]: %d bytes to read, but only %d bytes are available",datasize*nchan*nitem,bufAvailable);
+    }
+    else
+    {
+      swab(this_shn->decode_state->writebuf, this_shn->decode_state->writefub, datasize * nchan * nitem);
+      if (datasize*nchan*nitem <= bufAvailable) {
+        memcpy((void *)&this_shn->vars.buffer[this_shn->vars.bytes_in_buf],(const void *)this_shn->decode_state->writefub,datasize*nchan*nitem);
+        this_shn->vars.bytes_in_buf += datasize*nchan*nitem;
+        nwrite = nitem;
+      }
+      else
+        shn_debug("Buffer overrun in fwrite_type() [case 3]: %d bytes to read, but only %d bytes are available",datasize*nchan*nitem,bufAvailable);
+    }
+    break;
+  case TYPE_S16LH:
+  case TYPE_U16LH:
+    if(hilo)
+    {
+      swab(this_shn->decode_state->writebuf, this_shn->decode_state->writefub, datasize * nchan * nitem);
+      if (datasize*nchan*nitem <= bufAvailable) {
+        memcpy((void *)&this_shn->vars.buffer[this_shn->vars.bytes_in_buf],(const void *)this_shn->decode_state->writefub,datasize*nchan*nitem);
+        this_shn->vars.bytes_in_buf += datasize*nchan*nitem;
+        nwrite = nitem;
+      }
+      else
+        shn_debug("Buffer overrun in fwrite_type() [case 4]: %d bytes to read, but only %d bytes are available",datasize*nchan*nitem,bufAvailable);
+    }
+    else
+    {
+      if (datasize*nchan*nitem <= bufAvailable) {
+        memcpy((void *)&this_shn->vars.buffer[this_shn->vars.bytes_in_buf],(const void *)this_shn->decode_state->writebuf,datasize*nchan*nitem);
+        this_shn->vars.bytes_in_buf += datasize*nchan*nitem;
+        nwrite = nitem;
+      }
+      else
+        shn_debug("Buffer overrun in fwrite_type() [case 5]: %d bytes to read, but only %d bytes are available",datasize*nchan*nitem,bufAvailable);
+    }
+    break;
+  }
+
+  if(nwrite != nitem)
+    shn_error_fatal(this_shn,"Failed to write decompressed stream -\npossible corrupt or truncated file");
+}
+
+/*************/
+/* bitshifts */
+/*************/
+
+void fix_bitshift(buffer, nitem, bitshift, ftype) slong *buffer; int nitem,
+       bitshift, ftype; {
+  int i;
+
+  if(ftype == TYPE_AU1)
+    for(i = 0; i < nitem; i++)
+      buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
+  else if(ftype == TYPE_AU2)
+    for(i = 0; i < nitem; i++) {
+      if(buffer[i] >= 0)
+	buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
+      else if(buffer[i] == -1)
+	buffer[i] =  NEGATIVE_ULAW_ZERO;
+      else
+	buffer[i] = ulaw_outward[bitshift][buffer[i] + 129];
+    }
+  else
+    if(bitshift != 0)
+      for(i = 0; i < nitem; i++)
+	buffer[i] <<= bitshift;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/gtk.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,860 @@
+/*  gtk.c - functions to build and display GTK windows
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: gtk.c,v 1.27 2007/03/29 00:40:40 jason Exp $
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <audacious/util.h>
+#include <audacious/configdb.h>
+#include "shorten.h"
+
+#undef XMMS_SHN_LOAD_TEXTFILES
+#ifdef HAVE_DIRENT_H
+#  include <sys/types.h>
+#  include <dirent.h>
+#  ifdef HAVE_OPENDIR
+#    ifdef HAVE_READDIR
+#      ifdef HAVE_CLOSEDIR
+#        define XMMS_SHN_LOAD_TEXTFILES 1
+#      endif
+#    endif
+#  endif
+#endif
+
+static GtkWidget *shn_configurewin = NULL,
+		 *about_box,
+		 *vbox,
+		 *options_vbox,
+		 *miscellaneous_vbox,
+		 *seektables_vbox,
+		 *bbox,
+		 *notebook,
+		 *output_frame,
+		 *output_vbox,
+		 *output_label,
+		 *output_error_stderr,
+		 *output_error_window,
+		 *output_error_devnull,
+		 *misc_frame,
+		 *misc_vbox,
+		 *swap_bytes_toggle,
+		 *verbose_toggle,
+		 *textfile_toggle,
+		 *textfile_extensions_entry,
+		 *textfile_extensions_label,
+		 *textfile_extensions_hbox,
+		 *path_frame,
+		 *path_vbox,
+		 *path_label,
+		 *path_entry,
+		 *path_entry_hbox,
+		 *path_browse,
+		 *relative_path_label,
+		 *relative_path_entry,
+		 *relative_path_entry_hbox,
+		 *ok,
+		 *cancel,
+		 *apply;
+
+void shn_display_about(void)
+{
+	if (about_box != NULL)
+	{
+		gdk_window_raise(about_box->window);
+		return;
+	}
+
+	about_box = xmms_show_message(
+		(gchar *) "About " PACKAGE,
+		(gchar *) PACKAGE " version " VERSION "\n"
+			  "Copyright (C) 2000-2007 Jason Jordan <shnutils@freeshell.org>\n"
+			  "Portions Copyright (C) 1992-1995 Tony Robinson\n"
+			  "\n"
+			  "shorten utilities pages:\n"
+			  "\n"
+			  "http://www.etree.org/shnutils/\n"
+			  "http://shnutils.freeshell.org/",
+		(gchar *) "Cool",
+		FALSE, NULL, NULL);
+	g_signal_connect_swapped(GTK_OBJECT(about_box), "destroy",
+		gtk_widget_destroyed, &about_box);
+}
+
+void shn_configurewin_save(void)
+{
+	ConfigDb *cfg;
+	gchar *filename;
+
+	shn_cfg.error_output_method = ERROR_OUTPUT_DEVNULL;
+	if (GTK_TOGGLE_BUTTON(output_error_stderr)->active)
+		shn_cfg.error_output_method = ERROR_OUTPUT_STDERR;
+	else if (GTK_TOGGLE_BUTTON(output_error_window)->active)
+		shn_cfg.error_output_method = ERROR_OUTPUT_WINDOW;
+
+	g_free(shn_cfg.seek_tables_path);
+	shn_cfg.seek_tables_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(path_entry)));
+
+	g_free(shn_cfg.relative_seek_tables_path);
+	shn_cfg.relative_seek_tables_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(relative_path_entry)));
+
+	shn_cfg.verbose = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(verbose_toggle));
+
+	shn_cfg.swap_bytes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(swap_bytes_toggle));
+
+	shn_cfg.load_textfiles = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(textfile_toggle));
+
+	g_free(shn_cfg.textfile_extensions);
+	shn_cfg.textfile_extensions = g_strdup(gtk_entry_get_text(GTK_ENTRY(textfile_extensions_entry)));
+
+	filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL);
+	cfg = bmp_cfg_db_open();
+	bmp_cfg_db_set_int(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.error_output_method_config_name, shn_cfg.error_output_method);
+	bmp_cfg_db_set_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.verbose_config_name, shn_cfg.verbose);
+	bmp_cfg_db_set_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.seek_tables_path_config_name, shn_cfg.seek_tables_path);
+	bmp_cfg_db_set_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.relative_seek_tables_path_config_name, shn_cfg.relative_seek_tables_path);
+	bmp_cfg_db_set_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.swap_bytes_config_name, shn_cfg.swap_bytes);
+	bmp_cfg_db_set_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.load_textfiles_config_name, shn_cfg.load_textfiles);
+	bmp_cfg_db_set_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.textfile_extensions_config_name, shn_cfg.textfile_extensions);
+
+	bmp_cfg_db_close(cfg);
+	g_free(filename);
+}
+
+void shn_configurewin_apply()
+{
+	shn_configurewin_save();
+}
+
+void shn_configurewin_ok(void)
+{
+	shn_configurewin_save();
+	gtk_widget_destroy(shn_configurewin);
+}
+
+void shn_display_configure(void)
+{
+	if (shn_configurewin != NULL)
+	{
+		gdk_window_raise(shn_configurewin->window);
+		return;
+	}
+
+	shn_configurewin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_signal_connect(GTK_OBJECT(shn_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &shn_configurewin);
+	gtk_window_set_title(GTK_WINDOW(shn_configurewin), (gchar *)"SHN Player Configuration");
+	gtk_window_set_policy(GTK_WINDOW(shn_configurewin), FALSE, FALSE, FALSE);
+	gtk_container_border_width(GTK_CONTAINER(shn_configurewin), 10);
+
+	vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(shn_configurewin), vbox);
+
+	notebook = gtk_notebook_new();
+
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+	options_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(options_vbox), 5);
+
+	seektables_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(seektables_vbox), 5);
+
+	miscellaneous_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(miscellaneous_vbox), 5);
+
+/* begin error output box */
+
+	output_frame = gtk_frame_new((gchar *)" Error display options ");
+	gtk_container_set_border_width(GTK_CONTAINER(output_frame), 5);
+
+	output_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(output_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(output_frame), output_vbox);
+
+	output_label = gtk_label_new((gchar *)"When an error occurs, display it to:");
+	gtk_misc_set_alignment(GTK_MISC(output_label), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(output_label), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(output_vbox), output_label, FALSE, FALSE, 0);
+	gtk_widget_show(output_label);
+
+	output_error_window = gtk_radio_button_new_with_label(NULL, (gchar *)"a window");
+	if (shn_cfg.error_output_method == ERROR_OUTPUT_WINDOW)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(output_error_window), TRUE);
+	gtk_box_pack_start(GTK_BOX(output_vbox), output_error_window, FALSE, FALSE, 0);
+	gtk_widget_show(output_error_window);
+
+	output_error_stderr = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(output_error_window)), (gchar *)"stderr");
+	if (shn_cfg.error_output_method == ERROR_OUTPUT_STDERR)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(output_error_stderr), TRUE);
+	gtk_box_pack_start(GTK_BOX(output_vbox), output_error_stderr, FALSE, FALSE, 0);
+	gtk_widget_show(output_error_stderr);
+
+	output_error_devnull = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(output_error_window)), (gchar *)"/dev/null");
+	if (shn_cfg.error_output_method == ERROR_OUTPUT_DEVNULL)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(output_error_devnull), TRUE);
+	gtk_box_pack_start(GTK_BOX(output_vbox), output_error_devnull, FALSE, FALSE, 0);
+	gtk_widget_show(output_error_devnull);
+
+	gtk_widget_show(output_vbox);
+	gtk_widget_show(output_frame);
+
+/* end error output box */
+
+/* begin misc box */
+
+	misc_frame = gtk_frame_new((gchar *)" Miscellaneous options ");
+	gtk_container_set_border_width(GTK_CONTAINER(misc_frame), 5);
+
+	misc_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(misc_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(misc_frame), misc_vbox);
+
+	swap_bytes_toggle = gtk_check_button_new_with_label((gchar *)"Swap audio bytes (toggle if all you hear is static)");
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(swap_bytes_toggle), shn_cfg.swap_bytes);
+	gtk_box_pack_start(GTK_BOX(misc_vbox), swap_bytes_toggle, FALSE, FALSE, 0);
+	gtk_widget_show(swap_bytes_toggle);
+
+	verbose_toggle = gtk_check_button_new_with_label((gchar *)"Display debug info to stderr");
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(verbose_toggle), shn_cfg.verbose);
+	gtk_box_pack_start(GTK_BOX(misc_vbox), verbose_toggle, FALSE, FALSE, 0);
+	gtk_widget_show(verbose_toggle);
+
+	textfile_toggle = gtk_check_button_new_with_label((gchar *)"Load text files in file information box");
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(textfile_toggle), shn_cfg.load_textfiles);
+	gtk_box_pack_start(GTK_BOX(misc_vbox), textfile_toggle, FALSE, FALSE, 0);
+	gtk_widget_show(textfile_toggle);
+
+	textfile_extensions_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(textfile_extensions_hbox), 5);
+	gtk_box_pack_start(GTK_BOX(misc_vbox), textfile_extensions_hbox, FALSE, FALSE, 0);
+
+	textfile_extensions_label = gtk_label_new((gchar *)"     Text file extensions:");
+	gtk_misc_set_alignment(GTK_MISC(textfile_extensions_label), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(textfile_extensions_label), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(textfile_extensions_hbox), textfile_extensions_label, FALSE, FALSE, 0);
+	gtk_widget_show(textfile_extensions_label);
+
+	textfile_extensions_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(textfile_extensions_entry), shn_cfg.textfile_extensions);
+	gtk_box_pack_start(GTK_BOX(textfile_extensions_hbox), textfile_extensions_entry, TRUE, TRUE, 0);
+	gtk_widget_show(textfile_extensions_entry);
+
+	gtk_widget_show(textfile_extensions_hbox);
+	gtk_widget_show(misc_vbox);
+	gtk_widget_show(misc_frame);
+
+/* end misc box */
+
+/* begin seek table path box */
+
+	path_frame = gtk_frame_new((gchar *)" Alternate seek table file locations ");
+	gtk_container_set_border_width(GTK_CONTAINER(path_frame), 5);
+
+	path_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(path_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(path_frame), path_vbox);
+
+	relative_path_label = gtk_label_new((gchar *)"Relative seek table path:");
+	gtk_misc_set_alignment(GTK_MISC(relative_path_label), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(relative_path_label), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(path_vbox), relative_path_label, FALSE, FALSE, 0);
+	gtk_widget_show(relative_path_label);
+
+	relative_path_entry_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(relative_path_entry_hbox), 5);
+	gtk_box_pack_start(GTK_BOX(path_vbox), relative_path_entry_hbox, TRUE, TRUE, 0);
+
+	relative_path_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(relative_path_entry), shn_cfg.relative_seek_tables_path);
+	gtk_box_pack_start(GTK_BOX(relative_path_entry_hbox), relative_path_entry, TRUE, TRUE, 0);
+	gtk_widget_show(relative_path_entry);
+
+	path_label = gtk_label_new((gchar *)"\nAbsolute seek table path:");
+	gtk_misc_set_alignment(GTK_MISC(path_label), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(path_label), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(path_vbox), path_label, FALSE, FALSE, 0);
+	gtk_widget_show(path_label);
+
+	path_entry_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(path_entry_hbox), 5);
+	gtk_box_pack_start(GTK_BOX(path_vbox), path_entry_hbox, TRUE, TRUE, 0);
+
+	path_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(path_entry), shn_cfg.seek_tables_path);
+	gtk_box_pack_start(GTK_BOX(path_entry_hbox), path_entry, TRUE, TRUE, 0);
+	gtk_widget_show(path_entry);
+
+#if 0
+	path_browse = gtk_button_new_with_label("Browse");
+	gtk_signal_connect(GTK_OBJECT(path_browse), "clicked", GTK_SIGNAL_FUNC(path_browse_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(path_entry_hbox), path_browse, FALSE, FALSE, 0);
+	gtk_widget_show(path_browse);
+#endif
+
+	gtk_widget_show(relative_path_entry_hbox);
+	gtk_widget_show(path_entry_hbox);
+	gtk_widget_show(path_vbox);
+	gtk_widget_show(path_frame);
+
+/* end seek table path box */
+
+	gtk_box_pack_start(GTK_BOX(options_vbox), output_frame, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(seektables_vbox), path_frame, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(miscellaneous_vbox), misc_frame, TRUE, TRUE, 0);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), options_vbox, gtk_label_new((gchar *)"Error Display"));
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), seektables_vbox, gtk_label_new((gchar *)"Seek Tables"));
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), miscellaneous_vbox, gtk_label_new((gchar *)"Miscellaneous"));
+
+	bbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+	gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 0);
+
+	ok = gtk_button_new_with_label((gchar *)"OK");
+	gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(shn_configurewin_ok), NULL);
+	GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+	gtk_widget_show(ok);
+	gtk_widget_grab_default(ok);
+
+	cancel = gtk_button_new_with_label((gchar *)"Cancel");
+	gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(shn_configurewin));
+	GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+	gtk_widget_show(cancel);
+
+	apply = gtk_button_new_with_label((gchar *)"Apply");
+	gtk_signal_connect_object(GTK_OBJECT(apply), "clicked", GTK_SIGNAL_FUNC(shn_configurewin_apply), NULL);
+	GTK_WIDGET_SET_FLAGS(apply, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), apply, TRUE, TRUE, 0);
+	gtk_widget_show(apply);
+
+	gtk_widget_show(bbox);
+	gtk_widget_show(options_vbox);
+	gtk_widget_show(seektables_vbox);
+	gtk_widget_show(miscellaneous_vbox);
+	gtk_widget_show(notebook);
+	gtk_widget_show(vbox);
+	gtk_widget_show(shn_configurewin);
+}
+
+void shn_message_box(char *message)
+{
+	GtkWidget *mbox_win,
+		  *mbox_vbox1,
+		  *mbox_vbox2,
+		  *mbox_frame,
+		  *mbox_label,
+		  *mbox_bbox,
+		  *mbox_ok;
+
+	mbox_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_signal_connect(GTK_OBJECT(mbox_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &mbox_win);
+	gtk_window_set_title(GTK_WINDOW(mbox_win), (gchar *)"Shorten file information");
+	gtk_window_set_policy(GTK_WINDOW(mbox_win), FALSE, FALSE, FALSE);
+	gtk_container_border_width(GTK_CONTAINER(mbox_win), 10);
+
+	mbox_vbox1 = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(mbox_win), mbox_vbox1);
+
+	mbox_frame = gtk_frame_new((gchar *)" " PACKAGE " error ");
+	gtk_container_set_border_width(GTK_CONTAINER(mbox_frame), 5);
+	gtk_box_pack_start(GTK_BOX(mbox_vbox1), mbox_frame, FALSE, FALSE, 0);
+
+	mbox_vbox2 = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(mbox_vbox2), 5);
+	gtk_container_add(GTK_CONTAINER(mbox_frame), mbox_vbox2);
+
+	mbox_label = gtk_label_new((gchar *)message);
+	gtk_misc_set_alignment(GTK_MISC(mbox_label), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(mbox_label), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(mbox_vbox2), mbox_label, TRUE, TRUE, 0);
+	gtk_widget_show(mbox_label);
+
+	mbox_bbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(mbox_bbox), GTK_BUTTONBOX_SPREAD);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(mbox_bbox), 5);
+	gtk_box_pack_start(GTK_BOX(mbox_vbox2), mbox_bbox, FALSE, FALSE, 0);
+
+	mbox_ok = gtk_button_new_with_label((gchar *)"OK");
+	gtk_signal_connect_object(GTK_OBJECT(mbox_ok), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(mbox_win));
+	GTK_WIDGET_SET_FLAGS(mbox_ok, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(mbox_bbox), mbox_ok, TRUE, TRUE, 0);
+	gtk_widget_show(mbox_ok);
+	gtk_widget_grab_default(mbox_ok);
+
+	gtk_widget_show(mbox_bbox);
+	gtk_widget_show(mbox_vbox2);
+	gtk_widget_show(mbox_frame);
+	gtk_widget_show(mbox_vbox1);
+	gtk_widget_show(mbox_win);
+}
+
+void load_shntextfile(char *filename,int num,GtkWidget *shntxt_notebook)
+{
+	FILE *f;
+	char buffer[1024],*shortfilename;
+	int nchars;
+	GtkWidget *shntxt_frame,
+		  *shntxt_vbox,
+		  *shntxt_vbox_inner,
+//		  *shntxt_text,
+//		  *shntxt_table,
+//		  *shntxt_vscrollbar,
+		  *shntxt_filename_hbox,
+		  *shntxt_filename_entry,
+		  *shntxt_filename_label;
+
+	shn_debug("Loading text file '%s'",filename);
+
+	if ((shortfilename = strrchr(filename,'/')))
+		shortfilename++;
+	else
+		shortfilename = filename;
+
+	shntxt_vbox = gtk_vbox_new(FALSE, 10);
+
+	shn_snprintf(buffer,1024," %s ",shortfilename);
+
+	shntxt_frame = gtk_frame_new((gchar *)buffer);
+	gtk_container_set_border_width(GTK_CONTAINER(shntxt_frame), 10);
+	gtk_box_pack_start(GTK_BOX(shntxt_vbox), shntxt_frame, TRUE, TRUE, 0);
+
+	shntxt_vbox_inner = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(shntxt_vbox_inner), 5);
+	gtk_container_add(GTK_CONTAINER(shntxt_frame), shntxt_vbox_inner);
+
+/* begin filename */
+	shntxt_filename_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(shntxt_vbox_inner), shntxt_filename_hbox, FALSE, TRUE, 0);
+
+	shntxt_filename_label = gtk_label_new((gchar *)"Filename:");
+	gtk_box_pack_start(GTK_BOX(shntxt_filename_hbox), shntxt_filename_label, FALSE, TRUE, 0);
+	shntxt_filename_entry = gtk_entry_new();
+	gtk_editable_set_editable(GTK_EDITABLE(shntxt_filename_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(shntxt_filename_hbox), shntxt_filename_entry, TRUE, TRUE, 0);
+
+	gtk_entry_set_text(GTK_ENTRY(shntxt_filename_entry), filename);
+	gtk_editable_set_position(GTK_EDITABLE(shntxt_filename_entry), -1);
+/* end filename */
+
+#if 0
+	shntxt_text = gtk_text_new(NULL,NULL);
+
+	shntxt_table = gtk_table_new(2,2,FALSE);
+	gtk_container_add(GTK_CONTAINER(shntxt_vbox_inner), shntxt_table);
+
+	shntxt_vscrollbar = gtk_vscrollbar_new(GTK_TEXT(shntxt_text)->vadj);
+
+	gtk_text_set_editable(GTK_TEXT(shntxt_text),FALSE);
+	gtk_text_set_word_wrap(GTK_TEXT(shntxt_text),TRUE);
+
+	gtk_table_attach(GTK_TABLE(shntxt_table),shntxt_text, 0, 1, 0, 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+	gtk_table_attach(GTK_TABLE(shntxt_table),shntxt_vscrollbar, 1, 2, 0, 1, GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
+
+	gtk_widget_show(shntxt_vscrollbar);
+	gtk_widget_show(shntxt_text);
+	gtk_widget_show(shntxt_table);
+#endif
+	gtk_widget_show(shntxt_frame);
+	gtk_widget_show(shntxt_vbox);
+	gtk_widget_show(shntxt_vbox_inner);
+	gtk_widget_show(shntxt_filename_hbox);
+	gtk_widget_show(shntxt_filename_entry);
+	gtk_widget_show(shntxt_filename_label);
+
+	if ((f = fopen(filename,"rb")))
+	{
+		nchars = fread(buffer,1,1024,f);
+		while (nchars > 0)
+		{
+//			gtk_text_insert(GTK_TEXT(shntxt_text),NULL,NULL,NULL,buffer,nchars);
+			nchars = fread(buffer,1,1024,f);
+		}
+		fclose(f);
+	}
+	else
+	{
+		shn_snprintf(buffer,1024,"error loading file: '%s'",filename);
+//		gtk_text_insert(GTK_TEXT(shntxt_text),NULL,NULL,NULL,buffer,strlen(buffer));
+	}
+
+	shn_snprintf(buffer,1024,"Text file %d",num);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(shntxt_notebook), shntxt_vbox, gtk_label_new((gchar *)buffer));
+}
+
+void scan_for_textfiles(GtkWidget *this_notebook,char *dirname,int *filenum)
+{
+	char *ext,*textfile_exts,buffer[2048];
+	gchar *exts;
+	DIR *dp;
+	struct dirent *entry;
+
+	shn_debug("Searching for text files in directory '%s'",dirname);
+
+	if (NULL == (dp = opendir(dirname)))
+	{
+		shn_debug("Could not open directory '%s'",dirname);
+		return;
+	}
+
+	while ((entry = readdir(dp)))
+	{
+		exts = g_strdup(shn_cfg.textfile_extensions);
+
+		if ((ext = strrchr(entry->d_name,'.')))
+			ext++;
+		else
+			ext = "";
+
+		textfile_exts = strtok(exts,",");
+		while (textfile_exts)
+		{
+			if ((0 == strcmp(textfile_exts,ext)) || (0 == strcmp(textfile_exts,"")))
+			{
+				shn_snprintf(buffer,2048,"%s/%s",dirname,entry->d_name);
+
+				load_shntextfile(buffer,*filenum,this_notebook);
+				*filenum = *filenum + 1;
+				break;
+			}
+
+			textfile_exts = strtok(NULL,",");
+		}
+		
+		g_free(exts);
+	}
+
+	closedir(dp);
+}
+
+void load_shntextfiles(GtkWidget *this_notebook,char *filename)
+{
+#ifdef XMMS_SHN_LOAD_TEXTFILES
+	char *basedir,*uponedir;
+	int filenum = 1;
+
+	basedir = shn_get_base_directory(filename);
+
+	if (NULL == (uponedir = malloc((strlen(basedir) + 5) * sizeof(char))))
+	{
+		shn_debug("Could not allocate memory for search directories");
+		return;
+	}
+
+	shn_snprintf(uponedir,strlen(basedir) + 4,"%s/..",basedir);
+
+	scan_for_textfiles(this_notebook,basedir,&filenum);
+	scan_for_textfiles(this_notebook,uponedir,&filenum);
+
+	free(basedir);
+	free(uponedir);
+#else
+	shn_debug("Text file support is disabled on your platform because the\n"
+	      "appropriate functions were not found.  Please email me with\n"
+	      "the specifics of your platform, and I will try to support it.");
+#endif
+}
+
+
+void shn_display_info(shn_file *tmp_file)
+{
+	char props[BUF_SIZE];
+	char details[BUF_SIZE];
+	char props_label[BUF_SIZE];
+	char details_label[BUF_SIZE];
+	char misalignment[8];
+	char seektable_revision[8];
+	char id3v2_info[32];
+	GtkWidget *info_win,
+		  *info_notebook,
+		  *props_hbox,
+		  *props_vbox,
+		  *props_vbox_inner,
+		  *props_frame,
+		  *props_label_left,
+		  *props_label_right,
+		  *props_filename_hbox,
+		  *props_filename_label,
+		  *props_filename_entry,
+		  *details_hbox,
+		  *details_vbox,
+		  *details_vbox_inner,
+		  *details_frame,
+		  *details_label_left,
+		  *details_label_right,
+		  *details_filename_hbox,
+		  *details_filename_label,
+		  *details_filename_entry,
+		  *main_vbox,
+		  *info_bbox,
+		  *info_ok;
+
+	shn_snprintf(props_label,BUF_SIZE," Properties for %s ",
+		strrchr(tmp_file->wave_header.filename,'/') ?
+		strrchr(tmp_file->wave_header.filename,'/') + 1 :
+		tmp_file->wave_header.filename);
+
+	shn_snprintf(details_label,BUF_SIZE," Details for %s ",
+		strrchr(tmp_file->wave_header.filename,'/') ?
+		strrchr(tmp_file->wave_header.filename,'/') + 1 :
+		tmp_file->wave_header.filename);
+
+	shn_snprintf(misalignment,8,"%d",tmp_file->wave_header.data_size % CD_BLOCK_SIZE);
+
+	if (NO_SEEK_TABLE != tmp_file->seek_header.version)
+		shn_snprintf(seektable_revision,8,"%d",tmp_file->seek_header.version);
+
+	shn_snprintf(id3v2_info,32,"yes (%ld bytes)",tmp_file->wave_header.id3v2_tag_size);
+
+	shn_snprintf(props,BUF_SIZE,
+		"%s\n"
+		"%s\n"
+		"%s\n"
+		"%0.4f\n"
+		"\n"
+		"%s\n"
+		"%s\n"
+		"%s bytes\n"
+		"%s\n"
+		"\n"
+		"%s\n"
+		"%s\n"
+		"\n"
+		"%s",
+		tmp_file->wave_header.m_ss,
+		(tmp_file->vars.seek_table_entries == NO_SEEK_TABLE)?"no":"yes",
+		(tmp_file->seek_header.version == NO_SEEK_TABLE)?"n/a":seektable_revision,
+		(double)tmp_file->wave_header.actual_size/(double)tmp_file->wave_header.total_size,
+		(PROB_NOT_CD(tmp_file->wave_header))?"no":"yes",
+		(PROB_NOT_CD(tmp_file->wave_header))?"n/a":((PROB_BAD_BOUND(tmp_file->wave_header))?"no":"yes"),
+		(PROB_NOT_CD(tmp_file->wave_header))?"n/a":misalignment,
+		(PROB_NOT_CD(tmp_file->wave_header))?"n/a":((PROB_TOO_SHORT(tmp_file->wave_header))?"no":"yes"),
+		(PROB_HDR_NOT_CANONICAL(tmp_file->wave_header))?"yes":"no",
+		(PROB_EXTRA_CHUNKS(tmp_file->wave_header))?"yes":"no",
+		(tmp_file->wave_header.file_has_id3v2_tag)?id3v2_info:"no"
+		);
+
+	shn_snprintf(details,BUF_SIZE,
+		"\n"
+		"0x%04x (%s)\n"
+		"%hu\n"
+		"%hu\n"
+		"%lu\n"
+		"%lu\n"
+		"%lu bytes/sec\n"
+		"%hu\n"
+		"%d bytes\n"
+		"%lu bytes\n"
+		"%lu bytes\n"
+		"%lu bytes\n"
+		"%lu bytes",
+		tmp_file->wave_header.wave_format,
+		shn_format_to_str(tmp_file->wave_header.wave_format),
+		tmp_file->wave_header.channels,
+		tmp_file->wave_header.bits_per_sample,
+		tmp_file->wave_header.samples_per_sec,
+		tmp_file->wave_header.avg_bytes_per_sec,
+		tmp_file->wave_header.rate,
+		tmp_file->wave_header.block_align,
+		tmp_file->wave_header.header_size,
+		tmp_file->wave_header.data_size,
+		tmp_file->wave_header.chunk_size,
+		tmp_file->wave_header.total_size,
+		tmp_file->wave_header.actual_size
+		);
+
+	info_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_signal_connect(GTK_OBJECT(info_win), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &info_win);
+	gtk_window_set_title(GTK_WINDOW(info_win), (gchar *)"Shorten file information");
+	gtk_window_set_policy(GTK_WINDOW(info_win), FALSE, FALSE, FALSE);
+	gtk_container_border_width(GTK_CONTAINER(info_win), 10);
+
+	main_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(info_win), main_vbox);
+
+	info_notebook = gtk_notebook_new();
+	gtk_container_add(GTK_CONTAINER(main_vbox), info_notebook);
+
+/* begin properties page */
+
+	props_vbox = gtk_vbox_new(FALSE, 10);
+
+	props_frame = gtk_frame_new((gchar *)props_label);
+	gtk_container_set_border_width(GTK_CONTAINER(props_frame), 10);
+	gtk_box_pack_start(GTK_BOX(props_vbox), props_frame, TRUE, TRUE, 0);
+
+	props_vbox_inner = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(props_vbox_inner), 5);
+	gtk_container_add(GTK_CONTAINER(props_frame), props_vbox_inner);
+
+/* begin filename */
+	props_filename_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(props_vbox_inner), props_filename_hbox, FALSE, TRUE, 0);
+
+	props_filename_label = gtk_label_new((gchar *)"Filename:");
+	gtk_box_pack_start(GTK_BOX(props_filename_hbox), props_filename_label, FALSE, TRUE, 0);
+	props_filename_entry = gtk_entry_new();
+	gtk_editable_set_editable(GTK_EDITABLE(props_filename_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(props_filename_hbox), props_filename_entry, TRUE, TRUE, 0);
+
+	gtk_entry_set_text(GTK_ENTRY(props_filename_entry), tmp_file->wave_header.filename);
+	gtk_editable_set_position(GTK_EDITABLE(props_filename_entry), -1);
+/* end filename */
+
+	props_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(props_vbox_inner), props_hbox, TRUE, TRUE, 0);
+
+	props_label_left = gtk_label_new((gchar *)
+		"Length:\n"
+		"Seekable:\n"
+		"Seek table revision:\n"
+		"Compression ratio:\n"
+		"CD-quality properties:\n"
+		"  CD-quality:\n"
+		"  Cut on sector boundary:\n"
+		"  Sector misalignment:\n"
+		"  Long enough to be burned:\n"
+		"WAVE properties:\n"
+		"  Non-canonical header:\n"
+		"  Extra RIFF chunks:\n"
+		"Possible problems:\n"
+		"  File contains ID3v2 tag:"
+		);
+
+	props_label_right = gtk_label_new((gchar *)props);
+
+	gtk_misc_set_alignment(GTK_MISC(props_label_left), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(props_label_left), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(props_hbox), props_label_left, TRUE, TRUE, 0);
+	gtk_widget_show(props_label_left);
+
+	gtk_misc_set_alignment(GTK_MISC(props_label_right), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(props_label_right), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(props_hbox), props_label_right, TRUE, TRUE, 0);
+	gtk_widget_show(props_label_right);
+
+/* end properties page */
+
+/* begin details page */
+
+	details_vbox = gtk_vbox_new(FALSE, 10);
+
+	details_frame = gtk_frame_new((gchar *)details_label);
+	gtk_container_set_border_width(GTK_CONTAINER(details_frame), 10);
+	gtk_box_pack_start(GTK_BOX(details_vbox), details_frame, TRUE, TRUE, 0);
+
+	details_vbox_inner = gtk_vbox_new(FALSE, 10);
+	gtk_container_set_border_width(GTK_CONTAINER(details_vbox_inner), 5);
+	gtk_container_add(GTK_CONTAINER(details_frame), details_vbox_inner);
+
+/* begin filename */
+	details_filename_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(details_vbox_inner), details_filename_hbox, FALSE, TRUE, 0);
+
+	details_filename_label = gtk_label_new((gchar *)"Filename:");
+	gtk_box_pack_start(GTK_BOX(details_filename_hbox), details_filename_label, FALSE, TRUE, 0);
+	details_filename_entry = gtk_entry_new();
+	gtk_editable_set_editable(GTK_EDITABLE(details_filename_entry), FALSE);
+	gtk_box_pack_start(GTK_BOX(details_filename_hbox), details_filename_entry, TRUE, TRUE, 0);
+
+	gtk_entry_set_text(GTK_ENTRY(details_filename_entry), tmp_file->wave_header.filename);
+	gtk_editable_set_position(GTK_EDITABLE(details_filename_entry), -1);
+/* end filename */
+
+	details_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_box_pack_start(GTK_BOX(details_vbox_inner), details_hbox, TRUE, TRUE, 0);
+
+	details_label_left = gtk_label_new((gchar *)
+		"\n"
+		"WAVE format:\n"
+		"Channels:\n"
+		"Bits per sample:\n"
+		"Samples per second:\n"
+		"Average bytes per second:\n"
+		"Rate (calculated):\n"
+		"Block align:\n"
+		"Header size:\n"
+		"WAVE data size:\n"
+		"Chunk size:\n"
+		"Total size (chunk size + 8):\n"
+		"Actual file size:"
+		);
+
+	details_label_right = gtk_label_new((gchar *)details);
+
+	gtk_misc_set_alignment(GTK_MISC(details_label_left), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(details_label_left), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(details_hbox), details_label_left, TRUE, TRUE, 0);
+	gtk_widget_show(details_label_left);
+
+	gtk_misc_set_alignment(GTK_MISC(details_label_right), 0, 0);
+	gtk_label_set_justify(GTK_LABEL(details_label_right), GTK_JUSTIFY_LEFT);
+	gtk_box_pack_start(GTK_BOX(details_hbox), details_label_right, TRUE, TRUE, 0);
+	gtk_widget_show(details_label_right);
+
+/* end details page */
+
+	info_bbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(info_bbox), GTK_BUTTONBOX_SPREAD);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(info_bbox), 5);
+	gtk_box_pack_start(GTK_BOX(main_vbox), info_bbox, FALSE, FALSE, 0);
+
+	info_ok = gtk_button_new_with_label((gchar *)"OK");
+	gtk_signal_connect_object(GTK_OBJECT(info_ok), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(info_win));
+	GTK_WIDGET_SET_FLAGS(info_ok, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(info_bbox), info_ok, TRUE, TRUE, 0);
+	gtk_widget_show(info_ok);
+	gtk_widget_grab_default(info_ok);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(info_notebook), props_vbox, gtk_label_new((gchar *)"Properties"));
+	gtk_notebook_append_page(GTK_NOTEBOOK(info_notebook), details_vbox, gtk_label_new((gchar *)"Details"));
+
+	gtk_widget_show(props_frame);
+	gtk_widget_show(props_hbox);
+	gtk_widget_show(props_vbox_inner);
+	gtk_widget_show(props_vbox);
+	gtk_widget_show(props_filename_hbox);
+	gtk_widget_show(props_filename_entry);
+	gtk_widget_show(props_filename_label);
+	gtk_widget_show(details_frame);
+	gtk_widget_show(details_hbox);
+	gtk_widget_show(details_vbox_inner);
+	gtk_widget_show(details_vbox);
+	gtk_widget_show(details_filename_hbox);
+	gtk_widget_show(details_filename_entry);
+	gtk_widget_show(details_filename_label);
+
+/* begin any text files pages */
+
+	if (shn_cfg.load_textfiles)
+		load_shntextfiles(info_notebook,tmp_file->wave_header.filename);
+
+/* end any text files pages */
+
+	gtk_notebook_set_page(GTK_NOTEBOOK(info_notebook), 0);
+
+	gtk_widget_show(info_notebook);
+	gtk_widget_show(main_vbox);
+	gtk_widget_show(info_bbox);
+	gtk_widget_show(info_win);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/id3v2.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,120 @@
+/*  id3v2.c - functions to handle ID3v2 tags prepended to shn files
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: id3v2.c,v 1.6 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdio.h>
+#include "shorten.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ID3V2_MAGIC "ID3"
+
+typedef struct {
+  char magic[3];
+  unsigned char version[2];
+  unsigned char flags[1];
+  unsigned char size[4];
+} _id3v2_header;
+
+int tagcmp(char *got,char *expected)
+/* compare got against expected, up to the length of expected */
+{
+  int i;
+
+  for (i=0;*(expected+i);i++) {
+    if (*(got+i) != *(expected+i))
+      return i+1;
+  }
+
+  return 0;
+}
+
+unsigned long synchsafe_int_to_ulong(unsigned char *buf)
+/* converts 4 bytes stored in synchsafe integer format to an unsigned long */
+{
+  return (unsigned long)(((buf[0] & 0x7f) << 21) | ((buf[1] & 0x7f) << 14) | ((buf[2] & 0x7f) << 7) | (buf[3] & 0x7f));
+}
+
+static unsigned long check_for_id3v2_tag(VFSFile *f)
+{
+  _id3v2_header id3v2_header;
+  unsigned long tag_size;
+
+  /* read an ID3v2 header's size worth of data */
+  if (sizeof(_id3v2_header) != vfs_fread(&id3v2_header,1,sizeof(_id3v2_header),f)) {
+    return 0;
+  }
+
+  /* verify this is an ID3v2 header */
+  if (tagcmp(id3v2_header.magic,ID3V2_MAGIC) ||
+      0xff == id3v2_header.version[0] || 0xff == id3v2_header.version[1] ||
+      0x80 <= id3v2_header.size[0] || 0x80 <= id3v2_header.size[1] ||
+      0x80 <= id3v2_header.size[2] || 0x80 <= id3v2_header.size[3])
+  {
+    return 0;
+  }
+
+  /* calculate and return ID3v2 tag size */
+  tag_size = synchsafe_int_to_ulong(id3v2_header.size);
+
+  return tag_size;
+}
+
+VFSFile *shn_open_and_discard_id3v2_tag(char *filename,int *file_has_id3v2_tag,long *id3v2_tag_size)
+/* opens a file, and if it contains an ID3v2 tag, skips past it */
+{ 
+  VFSFile *f;
+  unsigned long tag_size;
+
+  if (NULL == (f = vfs_fopen(filename,"rb"))) {
+    return NULL;
+  }
+
+  if (file_has_id3v2_tag)
+    *file_has_id3v2_tag = 0;
+
+  if (id3v2_tag_size)
+    *id3v2_tag_size = 0;
+
+  /* check for ID3v2 tag on input */
+  if (0 == (tag_size = check_for_id3v2_tag(f))) {
+    vfs_fclose(f);
+    return vfs_fopen(filename,"rb");
+  }
+
+  if (file_has_id3v2_tag)
+    *file_has_id3v2_tag = 2;
+
+  if (id3v2_tag_size)
+    *id3v2_tag_size = (long)(tag_size + sizeof(_id3v2_header));
+
+  shn_debug("Discarding %lu-byte ID3v2 tag at beginning of file '%s'.",tag_size+sizeof(_id3v2_header),filename);
+
+  if (0 != vfs_fseek(f,(long)tag_size,SEEK_CUR)) {
+    shn_debug("Error while discarding ID3v2 tag in file '%s'.",filename);
+    vfs_fclose(f);
+    return vfs_fopen(filename,"rb");
+  }
+
+  return f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/misc.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,148 @@
+/*  misc.c - miscellaneous functions
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: misc.c,v 1.14 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "shorten.h"
+
+void shn_snprintf(char *dest,int maxlen,char *formatstr, ...)
+/* acts like snprintf, but makes 100% sure the string is NULL-terminated */
+{
+  va_list args;
+
+  va_start(args,formatstr);
+
+  shn_vsnprintf(dest,maxlen,formatstr,args);
+
+  dest[maxlen-1] = 0;
+
+  va_end(args);
+}
+
+int shn_filename_contains_a_dot(char *filename)
+{
+	char *slash,*dot;
+
+	dot = strrchr(filename,'.');
+	if (!dot)
+		return 0;
+
+	slash = strrchr(filename,'/');
+	if (!slash)
+		return 1;
+
+	if (slash < dot)
+		return 1;
+	else
+		return 0;
+}
+
+char *shn_get_base_filename(char *filename)
+{
+	char *b,*e,*p,*base;
+
+	b = strrchr(filename,'/');
+
+	if (b)
+		b++;
+	else
+		b = filename;
+
+	e = strrchr(filename,'.');
+
+	if (e < b)
+		e = filename + strlen(filename);
+
+	if (NULL == (base = malloc((e - b + 1) * sizeof(char))))
+	{
+		shn_debug("Could not allocate memory for base filename");
+		return NULL;
+	}
+
+	for (p=b;p<e;p++)
+		*(base + (p - b)) = *p;
+
+	*(base + (p - b)) = '\0';
+
+	return base;
+}
+
+char *shn_get_base_directory(char *filename)
+{
+	char *e,*p,*base;
+
+	e = strrchr(filename,'/');
+
+	if (!e)
+		e = filename;
+
+	if (NULL == (base = malloc((e - filename + 1) * sizeof(char))))
+	{
+		shn_debug("Could not allocate memory for base directory");
+		return NULL;
+	}
+
+	for (p=filename;p<e;p++)
+		*(base + (p - filename)) = *p;
+
+	*(base + (p - filename)) = '\0';
+
+	return base;
+}
+
+void shn_length_to_str(shn_file *info)
+/* converts length of file to a string in m:ss or m:ss.ff format */
+{
+  ulong newlength,rem1,rem2,frames,ms;
+  double tmp;
+
+  if (PROB_NOT_CD(info->wave_header)) {
+    newlength = (ulong)info->wave_header.exact_length;
+
+    tmp = info->wave_header.exact_length - (double)((ulong)info->wave_header.exact_length);
+    ms = (ulong)((tmp * 1000.0) + 0.5);
+
+    if (1000 == ms) {
+      ms = 0;
+      newlength++;
+    }
+
+    shn_snprintf(info->wave_header.m_ss,16,"%lu:%02lu.%03lu",newlength/60,newlength%60,ms);
+  }
+  else {
+    newlength = info->wave_header.length;
+
+    rem1 = info->wave_header.data_size % CD_RATE;
+    rem2 = rem1 % CD_BLOCK_SIZE;
+
+    frames = rem1 / CD_BLOCK_SIZE;
+    if (rem2 >= (CD_BLOCK_SIZE / 2))
+      frames++;
+
+    if (frames == CD_BLOCKS_PER_SEC) {
+      frames = 0;
+      newlength++;
+    }
+
+    shn_snprintf(info->wave_header.m_ss,16,"%lu:%02lu.%02lu",newlength/60,newlength%60,frames);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/output.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,101 @@
+/*  output.c - functions for message and error output
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: output.c,v 1.11 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "shorten.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+void print_lines(char *prefix,char *message)
+{
+  char *head, *tail;
+
+  head = tail = message;
+  while (*head != '\0') {
+    if (*head == '\n') {
+      *head = '\0';
+      fprintf(stderr,"%s%s\n",prefix,tail);
+      tail = head + 1;
+    }
+    head++;
+  }
+  fprintf(stderr,"%s%s\n",prefix,tail);
+}
+
+void shn_error(char *msg, ...)
+{
+  va_list args;
+  char msgbuf[BUF_SIZE];
+
+  va_start(args,msg);
+
+  shn_vsnprintf(msgbuf,BUF_SIZE,msg,args);
+
+  switch (shn_cfg.error_output_method) {
+    case ERROR_OUTPUT_STDERR:
+      print_lines(PACKAGE ": ",msgbuf);
+      break;
+    case ERROR_OUTPUT_WINDOW:
+      shn_message_box(msgbuf);
+      break;
+    default:
+      if (0 != shn_cfg.verbose)
+        print_lines(PACKAGE " [error]: ",msgbuf);
+  }
+
+  va_end(args);
+}
+
+void shn_debug(char *msg, ...)
+{
+  va_list args;
+  char msgbuf[BUF_SIZE];
+
+  va_start(args,msg);
+
+  shn_vsnprintf(msgbuf,BUF_SIZE,msg,args);
+
+  if (0 != shn_cfg.verbose)
+    print_lines(PACKAGE " [debug]: ",msgbuf);
+
+  va_end(args);
+}
+
+void shn_error_fatal(shn_file *this_shn,char *complaint, ...)
+{
+  va_list args;
+
+  va_start(args,complaint);
+
+  if (NULL != this_shn) {
+    if (0 == this_shn->vars.fatal_error) {
+      this_shn->vars.fatal_error = 1;
+      this_shn->vars.going = 0;
+      shn_vsnprintf(this_shn->vars.fatal_error_msg,BUF_SIZE,complaint,args);
+    }
+  }
+
+  va_end(args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/seek.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,279 @@
+/*  seek.c - functions related to real-time seeking
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: seek.c,v 1.18 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <audacious/util.h>
+#include "shorten.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ID3V1_TAG_SIZE 128
+
+shn_seek_entry *shn_seek_entry_search(shn_seek_entry *table,ulong goal,ulong min,ulong max,ulong resolution)
+{
+	ulong med = (min + max) / 2;
+	shn_seek_entry *middle = table + med;
+	ulong sample = shn_uchar_to_ulong_le(middle->data);
+
+	shn_debug("Examining seek table entry %lu with sample %lu (min/max = %lu/%lu, goal sample is %lu, resolution is %lu samples)",med,sample,min,max,goal,resolution);
+
+	if (goal < sample)
+		return shn_seek_entry_search(table,goal,min,med-1,resolution);
+	if (goal > sample + resolution)
+		return shn_seek_entry_search(table,goal,med+1,max,resolution);
+	return middle;
+}
+
+int load_separate_seek_table_generic(char *filename,shn_file *this_shn)
+{
+	VFSFile *f;
+	slong seek_table_len;
+
+	shn_debug("Looking for seek table in separate file: '%s'",filename);
+
+	if (!(f=vfs_fopen(filename,"rb")))
+	{
+		return 0;
+	}
+
+	vfs_fseek(f,0,SEEK_END);
+	seek_table_len = (slong)vfs_ftell(f) - SEEK_HEADER_SIZE;
+	vfs_fseek(f,0,SEEK_SET);
+
+	if (vfs_fread((void *)this_shn->seek_header.data,1,SEEK_HEADER_SIZE,f) == SEEK_HEADER_SIZE)
+	{
+		this_shn->seek_header.version = (slong)shn_uchar_to_ulong_le(this_shn->seek_header.data+4);
+		this_shn->seek_header.shnFileSize = shn_uchar_to_ulong_le(this_shn->seek_header.data+8);
+		if (memcmp(this_shn->seek_header.data,SEEK_HEADER_SIGNATURE,strlen(SEEK_HEADER_SIGNATURE)) == 0)
+		{
+			if (this_shn->seek_header.shnFileSize != this_shn->wave_header.actual_size)
+			{
+				shn_debug("warning: Seek table expected .shn file size %lu differs from actual .shn file size %lu - seek table might not belong to this file",
+					this_shn->seek_header.shnFileSize,this_shn->wave_header.actual_size);
+			}
+
+			if ((this_shn->seek_table = malloc(seek_table_len)))
+			{
+				if (vfs_fread((void *)this_shn->seek_table,1,seek_table_len,f) == seek_table_len)
+				{
+					shn_debug("Successfully loaded seek table in separate file: '%s'",filename);
+
+					this_shn->vars.seek_table_entries = seek_table_len / SEEK_ENTRY_SIZE;
+
+					if (this_shn->vars.seek_table_entries > 1)
+						this_shn->vars.seek_resolution = shn_uchar_to_ulong_le(this_shn->seek_table->data+SEEK_ENTRY_SIZE);
+					else
+						this_shn->vars.seek_resolution = SEEK_RESOLUTION;
+
+					vfs_fclose(f);
+
+					return 1;
+				}
+			}
+		}
+	}
+
+	vfs_fclose(f);
+	return 0;
+}
+
+int load_appended_seek_table(shn_file *this_shn,char *filename,long bytes_from_end)
+{
+	switch (bytes_from_end)
+	{
+		case 0:
+			shn_debug("Looking for seek table appended to file: '%s'",filename);
+			break;
+		case ID3V1_TAG_SIZE:
+			shn_debug("Looking for seek table hidden behind an ID3v1 tag at the end of file: '%s'",filename);
+			break;
+		default:
+			shn_debug("Looking for seek table located %ld bytes from the end of file: '%s'",bytes_from_end,filename);
+			break;
+	}
+
+	vfs_fseek(this_shn->vars.fd,-(SEEK_TRAILER_SIZE+bytes_from_end),SEEK_END);
+	if (vfs_fread((void *)this_shn->seek_trailer.data,1,SEEK_TRAILER_SIZE,this_shn->vars.fd) == SEEK_TRAILER_SIZE)
+	{
+		this_shn->seek_trailer.seekTableSize = shn_uchar_to_ulong_le(this_shn->seek_trailer.data);
+		if (memcmp(this_shn->seek_trailer.data+4,SEEK_TRAILER_SIGNATURE,strlen(SEEK_TRAILER_SIGNATURE)) == 0)
+		{
+			vfs_fseek(this_shn->vars.fd,-(this_shn->seek_trailer.seekTableSize+bytes_from_end),SEEK_END);
+			this_shn->seek_trailer.seekTableSize -= (SEEK_HEADER_SIZE + SEEK_TRAILER_SIZE);
+			if (vfs_fread((void *)this_shn->seek_header.data,1,SEEK_HEADER_SIZE,this_shn->vars.fd) == SEEK_HEADER_SIZE)
+			{
+				this_shn->seek_header.version = (slong)shn_uchar_to_ulong_le(this_shn->seek_header.data+4);
+				this_shn->seek_header.shnFileSize = shn_uchar_to_ulong_le(this_shn->seek_header.data+8);
+				if ((this_shn->seek_table = malloc(this_shn->seek_trailer.seekTableSize)))
+				{
+					if (vfs_fread((void *)this_shn->seek_table,1,this_shn->seek_trailer.seekTableSize,this_shn->vars.fd) == this_shn->seek_trailer.seekTableSize)
+					{
+						shn_debug("Successfully loaded seek table appended to file: '%s'",filename);
+
+						this_shn->vars.seek_table_entries = this_shn->seek_trailer.seekTableSize / SEEK_ENTRY_SIZE;
+
+						if (this_shn->vars.seek_table_entries > 1)
+							this_shn->vars.seek_resolution = shn_uchar_to_ulong_le(this_shn->seek_table->data+SEEK_ENTRY_SIZE);
+						else
+							this_shn->vars.seek_resolution = SEEK_RESOLUTION;
+
+						return 1;
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int load_separate_seek_table_samedir(shn_file *this_shn,char *filename)
+{
+	char *altfilename,*basefile,*basedir;
+
+	if (!(basefile = shn_get_base_filename(filename)))
+	{
+		return 0;
+	}
+
+	if (!(basedir = shn_get_base_directory(filename)))
+	{
+		free(basefile);
+		return 0;
+	}
+
+	if (!(altfilename = malloc(strlen(basedir)+strlen(basefile)+sizeof(SEEK_SUFFIX)+3)))
+	{
+		shn_debug("Could not allocate memory for same dir filename");
+		free(basefile);
+		free(basedir);
+		return 0;
+	}
+
+	sprintf(altfilename,"%s/%s.%s",basedir,basefile,SEEK_SUFFIX);
+
+	free(basefile);
+	free(basedir);
+
+	if (load_separate_seek_table_generic(altfilename,this_shn))
+	{
+		free(altfilename);
+		return 1;
+	}
+
+	free(altfilename);
+	return 0;
+}
+
+int load_separate_seek_table_relative(shn_file *this_shn,char *filename)
+{
+	char *altfilename,*basefile,*basedir;
+
+	if (0 == strcmp(shn_cfg.relative_seek_tables_path,""))
+		return 0;
+
+	if (!(basefile = shn_get_base_filename(filename)))
+	{
+		return 0;
+	}
+
+	if (!(basedir = shn_get_base_directory(filename)))
+	{
+		free(basefile);
+		return 0;
+	}
+
+	if (!(altfilename = malloc(strlen(basedir)+strlen(shn_cfg.relative_seek_tables_path)+strlen(basefile)+sizeof(SEEK_SUFFIX)+4)))
+	{
+		shn_debug("Could not allocate memory for absolute filename");
+		free(basefile);
+		free(basedir);
+		return 0;
+	}
+
+	sprintf(altfilename,"%s/%s/%s.%s",basedir,shn_cfg.relative_seek_tables_path,basefile,SEEK_SUFFIX);
+
+	free(basefile);
+	free(basedir);
+
+	if (load_separate_seek_table_generic(altfilename,this_shn))
+	{
+		free(altfilename);
+		return 1;
+	}
+
+	free(altfilename);
+	return 0;
+}
+
+int load_separate_seek_table_absolute(shn_file *this_shn,char *filename)
+{
+	char *altfilename,*basefile;
+
+	if (!(basefile = shn_get_base_filename(filename)))
+	{
+		return 0;
+	}
+
+	if (!(altfilename = malloc(strlen(shn_cfg.seek_tables_path)+strlen(basefile)+sizeof(SEEK_SUFFIX)+3)))
+	{
+		shn_debug("Could not allocate memory for same dir filename");
+		free(basefile);
+		return 0;
+	}
+
+	sprintf(altfilename,"%s/%s.%s",shn_cfg.seek_tables_path,basefile,SEEK_SUFFIX);
+
+	free(basefile);
+
+	if (load_separate_seek_table_generic(altfilename,this_shn))
+	{
+		free(altfilename);
+		return 1;
+	}
+
+	free(altfilename);
+	return 0;
+}
+
+void shn_load_seek_table(shn_file *this_shn,char *filename)
+{
+	if (load_appended_seek_table(this_shn,filename,0))
+		return;
+
+	if (load_appended_seek_table(this_shn,filename,ID3V1_TAG_SIZE))
+		return;
+
+	if (load_separate_seek_table_samedir(this_shn,filename))
+		return;
+
+	if (load_separate_seek_table_relative(this_shn,filename))
+		return;
+
+	if (load_separate_seek_table_absolute(this_shn,filename))
+		return;
+
+	shn_debug("Could not find any seek tables");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/shn.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,1379 @@
+/*  shn.c - main functions for xmms-shn
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: shn.c,v 1.38 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <glib.h>
+#include <audacious/util.h>
+#include <audacious/configdb.h>
+#include "shorten.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+static void shn_about(void);
+static void shn_configure(void);
+static void shn_init(void);
+static int  shn_is_our_fd(char *, VFSFile *fd);
+static void shn_play(InputPlayback *);
+static void shn_stop(InputPlayback *);
+static void shn_seek(InputPlayback *, int);
+static void shn_pause(InputPlayback *, short);
+static void shn_get_file_info(char *,char **,int *);
+static void shn_display_file_info(char *);
+
+gchar *shn_fmts[] = { "shn", NULL };
+
+InputPlugin shn_ip =
+{
+	NULL,
+	NULL,
+	"SHN Player " VERSION,
+	shn_init,
+	shn_about,
+	shn_configure,
+	NULL,
+	NULL,
+	shn_play,
+	shn_stop,
+	shn_pause,
+	shn_seek,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	shn_get_file_info,
+	shn_display_file_info,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	shn_is_our_fd,
+	shn_fmts,
+};
+
+InputPlugin *shn_iplist[] = { &shn_ip, NULL };
+
+DECLARE_PLUGIN(shnplug, NULL, NULL, shn_iplist, NULL, NULL, NULL, NULL);
+
+shn_file *shnfile;
+shn_config shn_cfg;
+
+static pthread_t decode_thread;
+static gboolean audio_error = FALSE;
+
+static void shn_init()
+{
+	ConfigDb *cfg;
+
+	shn_cfg.error_output_method = ERROR_OUTPUT_DEVNULL;
+	shn_cfg.error_output_method_config_name = "error_output_method";
+	shn_cfg.seek_tables_path = NULL;
+	shn_cfg.seek_tables_path_config_name = "seek_tables_path";
+	shn_cfg.relative_seek_tables_path = NULL;
+	shn_cfg.relative_seek_tables_path_config_name = "relative_seek_tables_path";
+	shn_cfg.verbose = 0;
+	shn_cfg.verbose_config_name = "verbose";
+	shn_cfg.swap_bytes = 0;
+	shn_cfg.swap_bytes_config_name = "swap_bytes";
+	shn_cfg.load_textfiles = FALSE;
+	shn_cfg.load_textfiles_config_name = "load_textfiles";
+	shn_cfg.textfile_extensions = NULL;
+	shn_cfg.textfile_extensions_config_name = "textfile_extensions";
+
+	if ((cfg = bmp_cfg_db_open()) != 0)
+	{
+		bmp_cfg_db_get_int(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.error_output_method_config_name, &shn_cfg.error_output_method);
+		bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.verbose_config_name, &shn_cfg.verbose);
+		if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.seek_tables_path_config_name, &shn_cfg.seek_tables_path))
+			shn_cfg.seek_tables_path = g_strdup(g_get_home_dir());
+		if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.relative_seek_tables_path_config_name, &shn_cfg.relative_seek_tables_path))
+			shn_cfg.relative_seek_tables_path = g_strdup("");
+		bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.swap_bytes_config_name, &shn_cfg.swap_bytes);
+		bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.load_textfiles_config_name, &shn_cfg.load_textfiles);
+		if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.textfile_extensions_config_name, &shn_cfg.textfile_extensions))
+			shn_cfg.textfile_extensions = g_strdup("txt,nfo");
+		bmp_cfg_db_close(cfg);
+	}
+}
+
+static void shn_about()
+{
+	shn_display_about();
+}
+
+static void shn_configure()
+{
+	shn_display_configure();
+}
+
+int init_decode_state(shn_file *this_shn)
+{
+	if (this_shn->decode_state)
+	{
+		if (this_shn->decode_state->getbuf)
+		{
+			free(this_shn->decode_state->getbuf);
+			this_shn->decode_state->getbuf = NULL;
+		}
+
+		if (this_shn->decode_state->writebuf)
+		{
+			free(this_shn->decode_state->writebuf);
+			this_shn->decode_state->writebuf = NULL;
+		}
+
+		if (this_shn->decode_state->writefub)
+		{
+			free(this_shn->decode_state->writefub);
+			this_shn->decode_state->writefub = NULL;
+		}
+
+		free(this_shn->decode_state);
+		this_shn->decode_state = NULL;
+	}
+
+	if (!(this_shn->decode_state = malloc(sizeof(shn_decode_state))))
+	{
+		shn_debug("Could not allocate memory for decode state data structure");
+		return 0;
+	}
+
+	this_shn->decode_state->getbuf = NULL;
+	this_shn->decode_state->getbufp = NULL;
+	this_shn->decode_state->nbitget = 0;
+	this_shn->decode_state->nbyteget = 0;
+	this_shn->decode_state->gbuffer = 0;
+	this_shn->decode_state->writebuf = NULL;
+	this_shn->decode_state->writefub = NULL;
+	this_shn->decode_state->nwritebuf = 0;
+
+	this_shn->vars.bytes_in_buf = 0;
+
+	return 1;
+}
+
+int get_wave_header(shn_file *this_shn)
+{
+  slong  **buffer = NULL, **offset = NULL;
+  slong  lpcqoffset = 0;
+  int   version = FORMAT_VERSION, bitshift = 0;
+  int   ftype = TYPE_EOF;
+  char  *magic = MAGIC;
+  int   blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN;
+  int   i, chan, nwrap, nskip = DEFAULT_NSKIP;
+  int   *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT;
+  int   cmd;
+  int   internal_ftype;
+  int   cklen;
+  int   retval = 0;
+
+  if (!init_decode_state(this_shn))
+    return 0;
+
+    /***********************/
+    /* EXTRACT starts here */
+    /***********************/
+
+    /* read magic number */
+#ifdef STRICT_FORMAT_COMPATABILITY
+    if(FORMAT_VERSION < 2)
+    {
+      for(i = 0; i < strlen(magic); i++) {
+        if(getc_exit(this_shn->vars.fd) != magic[i])
+          return 0;
+        this_shn->vars.bytes_read++;
+      }
+
+      /* get version number */
+      version = getc_exit(this_shn->vars.fd);
+      this_shn->vars.bytes_read++;
+    }
+    else
+#endif /* STRICT_FORMAT_COMPATABILITY */
+    {
+      int nscan = 0;
+
+      version = MAX_VERSION + 1;
+      while(version > MAX_VERSION)
+      {
+        int byte = vfs_getc(this_shn->vars.fd);
+        this_shn->vars.bytes_read++;
+        if(byte == EOF)
+          return 0;
+        if(magic[nscan] != '\0' && byte == magic[nscan])
+          nscan++;
+        else
+          if(magic[nscan] == '\0' && byte <= MAX_VERSION)
+            version = byte;
+        else
+        {
+          if(byte == magic[0])
+            nscan = 1;
+          else
+          {
+            nscan = 0;
+          }
+         version = MAX_VERSION + 1;
+        }
+      }
+    }
+
+    /* check version number */
+    if(version > MAX_SUPPORTED_VERSION)
+      return 0;
+
+    /* set up the default nmean, ignoring the command line state */
+    nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN;
+
+    /* initialise the variable length file read for the compressed stream */
+    var_get_init(this_shn);
+    if (this_shn->vars.fatal_error)
+      return 0;
+
+    /* initialise the fixed length file write for the uncompressed stream */
+    fwrite_type_init(this_shn);
+
+    /* get the internal file type */
+    internal_ftype = UINT_GET(TYPESIZE, this_shn);
+
+    /* has the user requested a change in file type? */
+    if(internal_ftype != ftype) {
+      if(ftype == TYPE_EOF) {
+        ftype = internal_ftype;    /*  no problems here */
+      }
+      else {           /* check that the requested conversion is valid */
+        if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
+           internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3)
+        {
+          retval = 0;
+          goto got_enough_data;
+        }
+      }
+    }
+
+    nchan = UINT_GET(CHANSIZE, this_shn);
+    this_shn->vars.actual_nchan = nchan;
+
+    /* get blocksize if version > 0 */
+    if(version > 0)
+    {
+      int byte;
+      blocksize = UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2),this_shn);
+      maxnlpc = UINT_GET(LPCQSIZE, this_shn);
+      this_shn->vars.actual_maxnlpc = maxnlpc;
+      nmean = UINT_GET(0, this_shn);
+      this_shn->vars.actual_nmean = nmean;
+      nskip = UINT_GET(NSKIPSIZE, this_shn);
+      for(i = 0; i < nskip; i++)
+      {
+        byte = uvar_get(XBYTESIZE,this_shn);
+      }
+    }
+    else
+      blocksize = DEFAULT_BLOCK_SIZE;
+
+    nwrap = MAX(NWRAP, maxnlpc);
+
+    /* grab some space for the input buffer */
+    buffer  = long2d((ulong) nchan, (ulong) (blocksize + nwrap),this_shn);
+    if (this_shn->vars.fatal_error)
+      return 0;
+    offset  = long2d((ulong) nchan, (ulong) MAX(1, nmean),this_shn);
+    if (this_shn->vars.fatal_error) {
+      if (buffer) {
+        free(buffer);
+        buffer = NULL;
+      }
+      return 0;
+    }
+
+    for(chan = 0; chan < nchan; chan++)
+    {
+      for(i = 0; i < nwrap; i++)
+      	buffer[chan][i] = 0;
+      buffer[chan] += nwrap;
+    }
+
+    if(maxnlpc > 0) {
+      qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc)),this_shn);
+      if (this_shn->vars.fatal_error) {
+        if (buffer) {
+          free(buffer);
+          buffer = NULL;
+        }
+        if (offset) {
+          free(offset);
+          buffer = NULL;
+        }
+        return 0;
+      }
+    }
+
+    if(version > 1)
+      lpcqoffset = V2LPCQOFFSET;
+
+    init_offset(offset, nchan, MAX(1, nmean), internal_ftype);
+
+    /* get commands from file and execute them */
+    chan = 0;
+    while(1)
+    {
+      this_shn->vars.reading_function_code = 1;
+      cmd = uvar_get(FNSIZE,this_shn);
+      this_shn->vars.reading_function_code = 0;
+
+        switch(cmd)
+        {
+          case FN_ZERO:
+          case FN_DIFF0:
+          case FN_DIFF1:
+          case FN_DIFF2:
+          case FN_DIFF3:
+          case FN_QLPC:
+          {
+            slong coffset, *cbuffer = buffer[chan];
+            int resn = 0, nlpc, j;
+
+            if(cmd != FN_ZERO)
+            {
+              resn = uvar_get(ENERGYSIZE,this_shn);
+              if (this_shn->vars.fatal_error) {
+                retval = 0;
+                goto got_enough_data;
+              }
+              /* this is a hack as version 0 differed in definition of var_get */
+              if(version == 0)
+                resn--;
+            }
+
+            /* find mean offset : N.B. this code duplicated */
+            if(nmean == 0)
+              coffset = offset[chan][0];
+            else
+            {
+              slong sum = (version < 2) ? 0 : nmean / 2;
+              for(i = 0; i < nmean; i++)
+                sum += offset[chan][i];
+              if(version < 2)
+                coffset = sum / nmean;
+              else
+                coffset = ROUNDEDSHIFTDOWN(sum / nmean, bitshift);
+            }
+
+            switch(cmd)
+            {
+              case FN_ZERO:
+                for(i = 0; i < blocksize; i++)
+                  cbuffer[i] = 0;
+                break;
+              case FN_DIFF0:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + coffset;
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                break;
+              case FN_DIFF1:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + cbuffer[i - 1];
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                break;
+              case FN_DIFF2:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + (2 * cbuffer[i - 1] -	cbuffer[i - 2]);
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                break;
+              case FN_DIFF3:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + 3 * (cbuffer[i - 1] -  cbuffer[i - 2]) + cbuffer[i - 3];
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                break;
+              case FN_QLPC:
+                nlpc = uvar_get(LPCQSIZE,this_shn);
+                if (this_shn->vars.fatal_error) {
+                  retval = 0;
+                  goto got_enough_data;
+                }
+
+                for(i = 0; i < nlpc; i++) {
+                  qlpc[i] = var_get(LPCQUANT,this_shn);
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                for(i = 0; i < nlpc; i++)
+                  cbuffer[i - nlpc] -= coffset;
+                for(i = 0; i < blocksize; i++)
+                {
+                  slong sum = lpcqoffset;
+
+                  for(j = 0; j < nlpc; j++)
+                    sum += qlpc[j] * cbuffer[i - j - 1];
+                  cbuffer[i] = var_get(resn,this_shn) + (sum >> LPCQUANT);
+                  if (this_shn->vars.fatal_error) {
+                    retval = 0;
+                    goto got_enough_data;
+                  }
+                }
+                if(coffset != 0)
+                  for(i = 0; i < blocksize; i++)
+                    cbuffer[i] += coffset;
+                break;
+            }
+
+            /* store mean value if appropriate : N.B. Duplicated code */
+            if(nmean > 0)
+            {
+              slong sum = (version < 2) ? 0 : blocksize / 2;
+
+              for(i = 0; i < blocksize; i++)
+                sum += cbuffer[i];
+
+              for(i = 1; i < nmean; i++)
+                offset[chan][i - 1] = offset[chan][i];
+              if(version < 2)
+                offset[chan][nmean - 1] = sum / blocksize;
+              else
+                offset[chan][nmean - 1] = (sum / blocksize) << bitshift;
+            }
+
+			if (0 == chan) {
+              this_shn->vars.initial_file_position = this_shn->vars.last_file_position_no_really;
+              goto got_enough_data;
+            }
+
+            /* do the wrap */
+            for(i = -nwrap; i < 0; i++)
+              cbuffer[i] = cbuffer[i + blocksize];
+
+            fix_bitshift(cbuffer, blocksize, bitshift, internal_ftype);
+
+            if(chan == nchan - 1)
+            {
+              fwrite_type(buffer, ftype, nchan, blocksize, this_shn);
+              this_shn->vars.bytes_in_buf = 0;
+            }
+
+            chan = (chan + 1) % nchan;
+            break;
+          }
+          break;
+
+          case FN_BLOCKSIZE:
+            UINT_GET((int) (log((double) blocksize) / M_LN2), this_shn);
+            break;
+
+          case FN_VERBATIM:
+            cklen = uvar_get(VERBATIM_CKSIZE_SIZE,this_shn);
+
+            while (cklen--) {
+              if (this_shn->vars.bytes_in_header >= OUT_BUFFER_SIZE) {
+                  shn_debug("Unexpectedly large header - " PACKAGE " can only handle a maximum of %d bytes",OUT_BUFFER_SIZE);
+                  goto got_enough_data;
+              }
+              this_shn->vars.bytes_in_buf = 0;
+              this_shn->vars.header[this_shn->vars.bytes_in_header++] = (char)uvar_get(VERBATIM_BYTE_SIZE,this_shn);
+            }
+            retval = 1;
+            break;
+
+          case FN_BITSHIFT:
+            bitshift = uvar_get(BITSHIFTSIZE,this_shn);
+            this_shn->vars.actual_bitshift = bitshift;
+            break;
+
+          default:
+            goto got_enough_data;
+        }
+    }
+
+got_enough_data:
+
+    /* wind up */
+    var_get_quit(this_shn);
+    fwrite_type_quit(this_shn);
+
+    if (buffer) free((void *) buffer);
+    if (offset) free((void *) offset);
+    if(maxnlpc > 0 && qlpc)
+      free((void *) qlpc);
+
+    this_shn->vars.bytes_in_buf = 0;
+
+    return retval;
+}
+
+void shn_unload(shn_file *this_shn)
+{
+	int this_shn_is_shnfile = (this_shn == shnfile) ? 1 : 0;
+
+	if (this_shn)
+	{
+		if (this_shn->vars.fd)
+		{
+			vfs_fclose(this_shn->vars.fd);
+			this_shn->vars.fd = NULL;
+		}
+
+		if (this_shn->decode_state)
+		{
+			if (this_shn->decode_state->getbuf)
+			{
+				free(this_shn->decode_state->getbuf);
+				this_shn->decode_state->getbuf = NULL;
+			}
+
+			if (this_shn->decode_state->writebuf)
+			{
+				free(this_shn->decode_state->writebuf);
+				this_shn->decode_state->writebuf = NULL;
+			}
+
+			if (this_shn->decode_state->writefub)
+			{
+				free(this_shn->decode_state->writefub);
+				this_shn->decode_state->writefub = NULL;
+			}
+
+			free(this_shn->decode_state);
+			this_shn->decode_state = NULL;
+		}
+
+		if (this_shn->seek_table)
+		{
+			free(this_shn->seek_table);
+			this_shn->seek_table = NULL;
+		}
+
+		free(this_shn);
+		this_shn = NULL;
+		if (this_shn_is_shnfile)
+			shnfile = NULL;
+	}
+}
+
+shn_file *load_shn(InputPlayback *playback, char *filename, VFSFile *fd)
+{
+	shn_file *tmp_file;
+	shn_seek_entry *first_seek_table;
+
+	shn_debug("Loading file: '%s'", filename);
+
+	if (!(tmp_file = malloc(sizeof(shn_file))))
+	{
+		shn_debug("Could not allocate memory for SHN data structure");
+		return NULL;
+	}
+
+	memset(tmp_file, 0, sizeof(shn_file));
+
+	tmp_file->vars.fd = NULL;
+	tmp_file->vars.seek_to = -1;
+	tmp_file->vars.eof = 0;
+	tmp_file->vars.going = 0;
+	tmp_file->vars.playback = playback;
+	tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
+	tmp_file->vars.bytes_in_buf = 0;
+	tmp_file->vars.bytes_in_header = 0;
+	tmp_file->vars.reading_function_code = 0;
+	tmp_file->vars.initial_file_position = 0;
+	tmp_file->vars.last_file_position = 0;
+	tmp_file->vars.last_file_position_no_really = 0;
+	tmp_file->vars.bytes_read = 0;
+	tmp_file->vars.actual_bitshift = 0;
+	tmp_file->vars.actual_maxnlpc = 0;
+	tmp_file->vars.actual_nmean = 0;
+	tmp_file->vars.actual_nchan = 0;
+	tmp_file->vars.seek_offset = 0;
+
+	tmp_file->decode_state = NULL;
+
+	tmp_file->wave_header.filename = filename;
+	tmp_file->wave_header.wave_format = 0;
+	tmp_file->wave_header.channels = 0;
+	tmp_file->wave_header.block_align = 0;
+	tmp_file->wave_header.bits_per_sample = 0;
+	tmp_file->wave_header.samples_per_sec = 0;
+	tmp_file->wave_header.avg_bytes_per_sec = 0;
+	tmp_file->wave_header.rate = 0;
+	tmp_file->wave_header.header_size = 0;
+	tmp_file->wave_header.data_size = 0;
+	tmp_file->wave_header.file_has_id3v2_tag = 0;
+	tmp_file->wave_header.id3v2_tag_size = 0;
+
+	tmp_file->seek_header.version = NO_SEEK_TABLE;
+	tmp_file->seek_header.shnFileSize = 0;
+
+	tmp_file->seek_trailer.seekTableSize = 0;
+
+	tmp_file->seek_table = NULL;
+
+	if (!fd)
+	{
+		if (!(tmp_file->vars.fd = shn_open_and_discard_id3v2_tag(filename,&tmp_file->wave_header.file_has_id3v2_tag,&tmp_file->wave_header.id3v2_tag_size)))
+		{
+			shn_debug("Could not open file: '%s'",filename);
+			shn_unload(tmp_file);
+			return NULL;
+		}
+	}
+	else
+		tmp_file->vars.fd = fd;
+
+	if (0 == get_wave_header(tmp_file))
+	{
+		shn_debug("Unable to read WAVE header from file '%s'",filename);
+		shn_unload(tmp_file);
+		return NULL;
+	}
+
+	if (tmp_file->wave_header.file_has_id3v2_tag)
+	{
+		vfs_fseek(tmp_file->vars.fd,tmp_file->wave_header.id3v2_tag_size,SEEK_SET);
+		tmp_file->vars.bytes_read += tmp_file->wave_header.id3v2_tag_size;
+		tmp_file->vars.seek_offset = tmp_file->wave_header.id3v2_tag_size;
+	}
+    else
+	{
+		vfs_fseek(tmp_file->vars.fd,0,SEEK_SET);
+	}
+
+	if (0 == shn_verify_header(tmp_file))
+	{
+		shn_debug("Invalid WAVE header in file: '%s'",filename);
+		shn_unload(tmp_file);
+		return NULL;
+	}
+
+	if (tmp_file->decode_state)
+	{
+		free(tmp_file->decode_state);
+		tmp_file->decode_state = NULL;
+	}
+
+	shn_load_seek_table(tmp_file,filename);
+
+	if (NO_SEEK_TABLE != tmp_file->vars.seek_table_entries)
+	{
+		/* verify seek tables */
+
+		first_seek_table = (shn_seek_entry *)tmp_file->seek_table;
+
+		if (tmp_file->vars.actual_bitshift != shn_uchar_to_ushort_le(first_seek_table->data+22))
+		{
+			/* initial bitshift value in the file does not match the first bitshift value of the first seektable entry - seeking is broken */
+			shn_debug("Broken seek table detected (invalid bitshift) - seeking disabled for this file.");
+			tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
+		}
+		else if (tmp_file->vars.actual_nchan > 2)
+		{
+			/* nchan is greater than the number of such entries stored in a seek table entry - seeking won't work */
+			shn_debug("Broken seek table detected (nchan %d not in range [1 .. 2]) - seeking disabled for this file.",tmp_file->vars.actual_nchan);
+			tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
+		}
+		else if (tmp_file->vars.actual_maxnlpc > 3)
+		{
+			/* maxnlpc is greater than the number of such entries stored in a seek table entry - seeking won't work */
+			shn_debug("Broken seek table detected (maxnlpc %d not in range [0 .. 3]) - seeking disabled for this file.",tmp_file->vars.actual_maxnlpc);
+			tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
+		}
+		else if (tmp_file->vars.actual_nmean > 4)
+		{
+			/* nmean is greater than the number of such entries stored in a seek table entry - seeking won't work */
+			shn_debug("Broken seek table detected (nmean %d not in range [0 .. 4]) - seeking disabled for this file.",tmp_file->vars.actual_nmean);
+			tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
+		}
+		else
+		{
+			/* seek table appears to be valid - now adjust byte offsets in seek table to match the file */
+			tmp_file->vars.seek_offset += tmp_file->vars.initial_file_position - shn_uchar_to_ulong_le(first_seek_table->data+8);
+
+			if (0 != tmp_file->vars.seek_offset)
+			{
+				shn_debug("Adjusting seek table offsets by %ld bytes due to mismatch between seek table values and input file - seeking might not work correctly.",
+					tmp_file->vars.seek_offset);
+			}
+		}
+	}
+
+	shn_debug("Successfully loaded file: '%s'",filename);
+
+	return tmp_file;
+}
+
+static int shn_is_our_fd(char *fn, VFSFile *fd)
+{
+	char data[4];
+
+	if (vfs_fread((void *)data,1,4,fd) != 4)
+		return FALSE;
+
+	if (memcmp(data,MAGIC,4))
+		return FALSE;
+
+#if 0
+	if (!(tmp_file = load_shn(NULL, filename, fd)))
+		return FALSE;
+
+	shn_unload(tmp_file);
+#endif
+
+	return TRUE;
+}
+
+void swap_bytes(shn_file *this_shn,int bytes)
+{
+	int i;
+	uchar tmp;
+
+	for (i=0;i<bytes;i=i+2) {
+		tmp = this_shn->vars.buffer[i+1];
+		this_shn->vars.buffer[i+1] = this_shn->vars.buffer[i];
+		this_shn->vars.buffer[i] = tmp;
+	}
+}
+
+void write_and_wait(shn_file *this_shn,int block_size)
+{
+	int bytes_to_write,bytes_in_block,i;
+	InputPlayback *playback = this_shn->vars.playback;
+
+	if (this_shn->vars.bytes_in_buf < block_size)
+		return;
+
+	bytes_in_block = min(this_shn->vars.bytes_in_buf, block_size);
+
+	if (bytes_in_block <= 0)
+		return;
+
+	bytes_to_write = bytes_in_block;
+	while ((bytes_to_write + bytes_in_block) <= this_shn->vars.bytes_in_buf)
+		bytes_to_write += bytes_in_block;
+
+	shn_ip.add_vis_pcm(shn_ip.output->written_time(), (this_shn->wave_header.bits_per_sample == 16) ? FMT_S16_LE : FMT_U8,
+		this_shn->wave_header.channels, bytes_to_write, this_shn->vars.buffer);
+
+	while(shn_ip.output->buffer_free() < bytes_to_write && playback->playing && this_shn->vars.seek_to == -1)
+		xmms_usleep(10000);
+
+	if(playback->playing && this_shn->vars.seek_to == -1) {
+		if (shn_cfg.swap_bytes)
+			swap_bytes(this_shn, bytes_to_write);
+		shn_ip.output->write_audio(this_shn->vars.buffer, bytes_to_write);
+	} else
+		return;
+
+	/* shift data from end of buffer to the front */
+	this_shn->vars.bytes_in_buf -= bytes_to_write;
+
+	for(i=0;i<this_shn->vars.bytes_in_buf;i++)
+		this_shn->vars.buffer[i] = this_shn->vars.buffer[i+bytes_to_write];
+}
+
+static void *play_loop_shn(void *arg)
+{
+  slong  **buffer = NULL, **offset = NULL;
+  slong  lpcqoffset = 0;
+  int   version = FORMAT_VERSION, bitshift = 0;
+  int   ftype = TYPE_EOF;
+  char  *magic = MAGIC;
+  int   blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN;
+  int   i, chan, nwrap, nskip = DEFAULT_NSKIP;
+  int   *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT;
+  int   cmd;
+  int   internal_ftype;
+  shn_file *this_shn = shnfile;
+  int   blk_size;
+  int   cklen;
+  uchar tmp;
+  ulong seekto_offset;
+  InputPlayback *playback = this_shn->vars.playback;
+
+restart:
+
+  this_shn->vars.bytes_in_buf = 0;
+
+  if (!init_decode_state(this_shn))
+    goto exit_thread;
+
+  blk_size = 512 * (this_shn->wave_header.bits_per_sample / 8) * this_shn->wave_header.channels;
+
+    /***********************/
+    /* EXTRACT starts here */
+    /***********************/
+
+    /* read magic number */
+#ifdef STRICT_FORMAT_COMPATABILITY
+    if(FORMAT_VERSION < 2)
+    {
+      for(i = 0; i < strlen(magic); i++)
+        if(getc_exit(this_shn->vars.fd) != magic[i]) {
+          shn_error_fatal(this_shn,"Bad magic number");
+          goto exit_thread;
+        }
+
+      /* get version number */
+      version = getc_exit(this_shn->vars.fd);
+    }
+    else
+#endif /* STRICT_FORMAT_COMPATABILITY */
+    {
+      int nscan = 0;
+
+      version = MAX_VERSION + 1;
+      while(version > MAX_VERSION)
+      {
+  	int byte = vfs_getc(this_shn->vars.fd);
+ 	if(byte == EOF) {
+	  shn_error_fatal(this_shn,"No magic number");
+          goto exit_thread;
+        }
+	if(magic[nscan] != '\0' && byte == magic[nscan])
+          nscan++;
+	else
+        if(magic[nscan] == '\0' && byte <= MAX_VERSION)
+          version = byte;
+	else
+        {
+	  if(byte == magic[0])
+  	    nscan = 1;
+	  else
+          {
+	    nscan = 0;
+	  }
+	  version = MAX_VERSION + 1;
+	}
+      }
+    }
+
+    /* check version number */
+    if(version > MAX_SUPPORTED_VERSION) {
+      shn_error_fatal(this_shn,"Can't decode version %d", version);
+      goto exit_thread;
+    }
+
+    /* set up the default nmean, ignoring the command line state */
+    nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN;
+
+    /* initialise the variable length file read for the compressed stream */
+    var_get_init(this_shn);
+    if (this_shn->vars.fatal_error)
+      goto exit_thread;
+
+    /* initialise the fixed length file write for the uncompressed stream */
+    fwrite_type_init(this_shn);
+
+    /* get the internal file type */
+    internal_ftype = UINT_GET(TYPESIZE, this_shn);
+
+    /* has the user requested a change in file type? */
+    if(internal_ftype != ftype) {
+      if(ftype == TYPE_EOF)
+	ftype = internal_ftype;    /*  no problems here */
+      else             /* check that the requested conversion is valid */
+	if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
+	   internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3) {
+	  shn_error_fatal(this_shn,"Not able to perform requested output format conversion");
+          goto cleanup;
+        }
+    }
+
+    nchan = UINT_GET(CHANSIZE, this_shn);
+
+    /* get blocksize if version > 0 */
+    if(version > 0)
+    {
+      int byte;
+      blocksize = UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2),this_shn);
+      maxnlpc = UINT_GET(LPCQSIZE, this_shn);
+      nmean = UINT_GET(0, this_shn);
+      nskip = UINT_GET(NSKIPSIZE, this_shn);
+      for(i = 0; i < nskip; i++)
+      {
+        byte = uvar_get(XBYTESIZE,this_shn);
+      }
+    }
+    else
+      blocksize = DEFAULT_BLOCK_SIZE;
+
+    nwrap = MAX(NWRAP, maxnlpc);
+
+    /* grab some space for the input buffer */
+    buffer  = long2d((ulong) nchan, (ulong) (blocksize + nwrap),this_shn);
+    if (this_shn->vars.fatal_error)
+      goto exit_thread;
+    offset  = long2d((ulong) nchan, (ulong) MAX(1, nmean),this_shn);
+    if (this_shn->vars.fatal_error) {
+      if (buffer) {
+        free(buffer);
+        buffer = NULL;
+      }
+      goto exit_thread;
+    }
+
+    for(chan = 0; chan < nchan; chan++)
+    {
+      for(i = 0; i < nwrap; i++)
+      	buffer[chan][i] = 0;
+      buffer[chan] += nwrap;
+    }
+
+    if(maxnlpc > 0) {
+      qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc)),this_shn);
+      if (this_shn->vars.fatal_error) {
+        if (buffer) {
+          free(buffer);
+          buffer = NULL;
+        }
+        if (offset) {
+          free(offset);
+          buffer = NULL;
+        }
+        goto exit_thread;
+      }
+    }
+
+    if(version > 1)
+      lpcqoffset = V2LPCQOFFSET;
+
+    init_offset(offset, nchan, MAX(1, nmean), internal_ftype);
+
+    /* get commands from file and execute them */
+    chan = 0;
+    while(1)
+    {
+        cmd = uvar_get(FNSIZE,this_shn);
+        if (this_shn->vars.fatal_error)
+          goto cleanup;
+
+        switch(cmd)
+        {
+          case FN_ZERO:
+          case FN_DIFF0:
+          case FN_DIFF1:
+          case FN_DIFF2:
+          case FN_DIFF3:
+          case FN_QLPC:
+          {
+            slong coffset, *cbuffer = buffer[chan];
+            int resn = 0, nlpc, j;
+
+            if(cmd != FN_ZERO)
+            {
+              resn = uvar_get(ENERGYSIZE,this_shn);
+              if (this_shn->vars.fatal_error)
+                goto cleanup;
+              /* this is a hack as version 0 differed in definition of var_get */
+              if(version == 0)
+                resn--;
+            }
+
+            /* find mean offset : N.B. this code duplicated */
+            if(nmean == 0)
+              coffset = offset[chan][0];
+            else
+            {
+              slong sum = (version < 2) ? 0 : nmean / 2;
+              for(i = 0; i < nmean; i++)
+                sum += offset[chan][i];
+              if(version < 2)
+                coffset = sum / nmean;
+              else
+                coffset = ROUNDEDSHIFTDOWN(sum / nmean, bitshift);
+            }
+
+            switch(cmd)
+            {
+              case FN_ZERO:
+                for(i = 0; i < blocksize; i++)
+                  cbuffer[i] = 0;
+                break;
+              case FN_DIFF0:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + coffset;
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                break;
+              case FN_DIFF1:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + cbuffer[i - 1];
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                break;
+              case FN_DIFF2:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + (2 * cbuffer[i - 1] -	cbuffer[i - 2]);
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                break;
+              case FN_DIFF3:
+                for(i = 0; i < blocksize; i++) {
+                  cbuffer[i] = var_get(resn,this_shn) + 3 * (cbuffer[i - 1] -  cbuffer[i - 2]) + cbuffer[i - 3];
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                break;
+              case FN_QLPC:
+                nlpc = uvar_get(LPCQSIZE,this_shn);
+                if (this_shn->vars.fatal_error)
+                  goto cleanup;
+
+                for(i = 0; i < nlpc; i++) {
+                  qlpc[i] = var_get(LPCQUANT,this_shn);
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                for(i = 0; i < nlpc; i++)
+                  cbuffer[i - nlpc] -= coffset;
+                for(i = 0; i < blocksize; i++)
+                {
+                  slong sum = lpcqoffset;
+
+                  for(j = 0; j < nlpc; j++)
+                    sum += qlpc[j] * cbuffer[i - j - 1];
+                  cbuffer[i] = var_get(resn,this_shn) + (sum >> LPCQUANT);
+                  if (this_shn->vars.fatal_error)
+                    goto cleanup;
+                }
+                if(coffset != 0)
+                  for(i = 0; i < blocksize; i++)
+                    cbuffer[i] += coffset;
+                break;
+            }
+
+            /* store mean value if appropriate : N.B. Duplicated code */
+            if(nmean > 0)
+            {
+              slong sum = (version < 2) ? 0 : blocksize / 2;
+
+              for(i = 0; i < blocksize; i++)
+                sum += cbuffer[i];
+
+              for(i = 1; i < nmean; i++)
+                offset[chan][i - 1] = offset[chan][i];
+              if(version < 2)
+                offset[chan][nmean - 1] = sum / blocksize;
+              else
+                offset[chan][nmean - 1] = (sum / blocksize) << bitshift;
+            }
+
+            /* do the wrap */
+            for(i = -nwrap; i < 0; i++)
+              cbuffer[i] = cbuffer[i + blocksize];
+
+            fix_bitshift(cbuffer, blocksize, bitshift, internal_ftype);
+
+            if(chan == nchan - 1)
+            {
+              if (!playback->playing || this_shn->vars.fatal_error)
+                goto cleanup;
+
+              fwrite_type(buffer, ftype, nchan, blocksize, this_shn);
+
+              write_and_wait(this_shn,blk_size);
+
+              if (this_shn->vars.seek_to != -1)
+              {
+                shn_seek_entry *seek_info;
+                int j;
+
+                shn_debug("Seeking to %d:%02d",this_shn->vars.seek_to/60,this_shn->vars.seek_to%60);
+
+                seek_info = shn_seek_entry_search(this_shn->seek_table,this_shn->vars.seek_to * (ulong)this_shn->wave_header.samples_per_sec,0,
+							      (ulong)(this_shn->vars.seek_table_entries - 1),this_shn->vars.seek_resolution);
+
+                /* loop through number of channels in this file */
+                for (i=0;i<nchan;i++) {
+                  /* load the three sample buffer values for this channel */
+                  for (j=0;j<3;j++)
+                    buffer[i][j-3] = shn_uchar_to_slong_le(seek_info->data+32+12*i-4*j);
+
+                  /* load the variable number of offset history values for this channel */
+                  for (j=0;j<MAX(1,nmean);j++)
+                    offset[i][j]  = shn_uchar_to_slong_le(seek_info->data+48+16*i+4*j);
+                }
+
+                bitshift = shn_uchar_to_ushort_le(seek_info->data+22);
+
+                seekto_offset = shn_uchar_to_ulong_le(seek_info->data+8) + this_shn->vars.seek_offset;
+
+                vfs_fseek(this_shn->vars.fd,(slong)seekto_offset,SEEK_SET);
+                vfs_fread((uchar*) this_shn->decode_state->getbuf, 1, BUFSIZ, this_shn->vars.fd);
+
+                this_shn->decode_state->getbufp = this_shn->decode_state->getbuf + shn_uchar_to_ushort_le(seek_info->data+14);
+                this_shn->decode_state->nbitget = shn_uchar_to_ushort_le(seek_info->data+16);
+                this_shn->decode_state->nbyteget = shn_uchar_to_ushort_le(seek_info->data+12);
+                this_shn->decode_state->gbuffer = shn_uchar_to_ulong_le(seek_info->data+18);
+
+                this_shn->vars.bytes_in_buf = 0;
+
+                shn_ip.output->flush(this_shn->vars.seek_to * 1000);
+                this_shn->vars.seek_to = -1;
+              }
+
+            }
+            chan = (chan + 1) % nchan;
+            break;
+          }
+
+          break;
+
+          case FN_QUIT:
+            /* empty out last of buffer */
+            write_and_wait(this_shn,this_shn->vars.bytes_in_buf);
+
+            playback->eof = TRUE;
+
+            while (1)
+            {
+              if (!playback->playing)
+                goto finish;
+              if (this_shn->vars.seek_to != -1)
+              {
+                var_get_quit(this_shn);
+                fwrite_type_quit(this_shn);
+
+                if (buffer) free((void *) buffer);
+                if (offset) free((void *) offset);
+                if(maxnlpc > 0 && qlpc)
+                  free((void *) qlpc);
+
+                vfs_fseek(this_shn->vars.fd,0,SEEK_SET);
+                goto restart;
+              }
+              else
+                xmms_usleep(10000);
+            }
+
+            goto cleanup;
+            break;
+
+          case FN_BLOCKSIZE:
+            blocksize = UINT_GET((int) (log((double) blocksize) / M_LN2), this_shn);
+            if (this_shn->vars.fatal_error)
+              goto cleanup;
+            break;
+          case FN_BITSHIFT:
+            bitshift = uvar_get(BITSHIFTSIZE,this_shn);
+            if (this_shn->vars.fatal_error)
+              goto cleanup;
+            break;
+          case FN_VERBATIM:
+            cklen = uvar_get(VERBATIM_CKSIZE_SIZE,this_shn);
+            if (this_shn->vars.fatal_error)
+              goto cleanup;
+
+            while (cklen--) {
+              tmp = (uchar)uvar_get(VERBATIM_BYTE_SIZE,this_shn);
+              if (this_shn->vars.fatal_error)
+                goto cleanup;
+            }
+
+            break;
+
+          default:
+            shn_error_fatal(this_shn,"Sanity check fails trying to decode function: %d",cmd);
+            goto cleanup;
+        }
+    }
+
+cleanup:
+
+    write_and_wait(this_shn,this_shn->vars.bytes_in_buf);
+    shn_ip.output->buffer_free();
+    shn_ip.output->buffer_free();
+    xmms_usleep(10000);
+
+finish:
+
+    this_shn->vars.seek_to = -1;
+    playback->eof = TRUE;
+
+    /* wind up */
+    var_get_quit(this_shn);
+    fwrite_type_quit(this_shn);
+
+    if (buffer) free((void *) buffer);
+    if (offset) free((void *) offset);
+    if(maxnlpc > 0 && qlpc)
+      free((void *) qlpc);
+
+exit_thread:
+
+    pthread_exit(NULL);
+}
+
+static void shn_play(InputPlayback *playback)
+{
+	char *name, *temp;
+	char *filename = playback->filename;
+
+	audio_error = FALSE;
+
+	if (!(shnfile = load_shn(playback, playback->filename, NULL)))
+	{
+		shn_debug("Could not load file for playing: '%s'", playback->filename);
+		return;
+	}
+
+	vfs_fseek(shnfile->vars.fd,0,SEEK_SET);
+
+	playback->playing = TRUE;
+
+	if (shn_ip.output->open_audio((shnfile->wave_header.bits_per_sample == 16) ? FMT_S16_LE : FMT_U8, shnfile->wave_header.samples_per_sec, shnfile->wave_header.channels) == 0)
+	{
+		audio_error = TRUE;
+		shn_debug("Could not open audio device for playback (check your output plugin configuration)");
+		return;
+	}
+	temp = strrchr(filename, '/');
+	if (!temp)
+		temp = filename;
+	else
+		temp++;
+	name = malloc(strlen(temp) + 1);
+	strcpy(name, temp);
+	if (shn_filename_contains_a_dot(name))
+		*(strrchr(name,'.')) = '\0';
+	shn_ip.set_info(name, 1000 * shnfile->wave_header.length, 8 * shnfile->wave_header.rate, shnfile->wave_header.samples_per_sec, shnfile->wave_header.channels);
+	free(name);
+	shnfile->vars.seek_to = -1;
+	pthread_create(&decode_thread, NULL, play_loop_shn, NULL);
+}
+
+static void shn_stop(InputPlayback *playback)
+{
+	int was_fatal;
+	char error_msg[BUF_SIZE];
+
+	if (!shnfile)
+		return;
+
+	if ((was_fatal = shnfile->vars.fatal_error))
+		shn_snprintf(error_msg,BUF_SIZE,"%s.\nAffected file was:\n%s",shnfile->vars.fatal_error_msg,shnfile->wave_header.filename);
+
+	if (playback->playing || was_fatal)
+	{
+		playback->playing = FALSE;
+		pthread_join(decode_thread, NULL);
+		shn_ip.output->close_audio();
+		shn_unload(shnfile);
+	}
+
+	if (was_fatal)
+		shn_error(error_msg);
+}
+
+static void shn_pause(InputPlayback *playback, short p)
+{
+	playback->output->pause(p);
+}
+
+static void shn_seek(InputPlayback *playback, int time)
+{
+	if (NULL == shnfile)
+		return;
+
+	if (shnfile->vars.seek_table_entries == NO_SEEK_TABLE)
+	{
+		shn_error("Cannot seek to %d:%02d because there is no seek information for this file.",time/60,time%60);
+		return;
+	}
+
+	shnfile->vars.seek_to = time;
+
+	while (shnfile->vars.seek_to != -1)
+		xmms_usleep(10000);
+}
+
+static void shn_get_file_info(char *filename, char **title, int *length)
+{
+	char *name, *temp;
+	shn_file *tmp_file;
+
+	temp = strrchr(filename, '/');
+	if (!temp)
+		temp = filename;
+	else
+		temp++;
+
+	name = g_malloc(strlen(temp) + 1);
+	strcpy(name, temp);
+
+	if (shn_filename_contains_a_dot(name))
+		*(strrchr(name,'.')) = '\0';
+
+	*title = name;
+
+	*length = 0;
+
+	if (!(tmp_file = load_shn(NULL, filename, NULL)))
+	{
+		shn_debug("Could not get information from file: '%s'",filename);
+		return;
+	}
+
+	*length = 1000 * tmp_file->wave_header.length;
+
+	shn_unload(tmp_file);
+}
+
+static void shn_display_file_info(char *filename)
+{
+	shn_file *tmp_file;
+
+	if (!(tmp_file = load_shn(NULL, filename, NULL)))
+	{
+		shn_debug("Could not get information from file: '%s'",filename);
+		return;
+	}
+
+	shn_display_info(tmp_file);
+
+	shn_unload(tmp_file);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/shn.h	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,293 @@
+/*  xmms-shn - a shorten (.shn) plugin for XMMS
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: shn.h,v 1.27 2007/03/23 05:49:48 jason Exp $
+ */
+
+#ifndef _SHN_H
+#define _SHN_H
+
+#include <pthread.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <audacious/plugin.h>
+#include <audacious/vfs.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define shn_vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
+
+#define	min(a,b)			(((a)<(b))?(a):(b))
+
+#define XMMS_SHN_VERSION_TAG		"xmms-shn_v2"
+
+/* surely no headers will be this large.  right?  RIGHT?  */
+#define OUT_BUFFER_SIZE			16384
+
+#define BUF_SIZE                        4096
+
+#define	ERROR_OUTPUT_DEVNULL		0
+#define	ERROR_OUTPUT_STDERR		1
+#define	ERROR_OUTPUT_WINDOW		2
+
+#define	SEEK_SUFFIX			"skt"
+
+#define	NO_SEEK_TABLE			-1
+
+#define	SEEK_HEADER_SIGNATURE		"SEEK"
+#define	SEEK_TRAILER_SIGNATURE		"SHNAMPSK"
+
+#define SEEK_HEADER_SIZE		12
+#define SEEK_TRAILER_SIZE		12
+#define SEEK_ENTRY_SIZE			80
+#define SEEK_RESOLUTION			25600
+
+#define WAVE_RIFF                       (0x46464952)     /* 'RIFF' in little-endian */
+#define WAVE_WAVE                       (0x45564157)     /* 'WAVE' in little-endian */
+#define WAVE_FMT                        (0x20746d66)     /* ' fmt' in little-endian */
+#define WAVE_DATA                       (0x61746164)     /* 'data' in little-endian */
+
+#define AIFF_FORM                       (0x4D524F46)     /* 'FORM' in little-endian */
+
+#define WAVE_FORMAT_UNKNOWN             (0x0000)
+#define WAVE_FORMAT_PCM                 (0x0001)
+#define WAVE_FORMAT_ADPCM               (0x0002)
+#define WAVE_FORMAT_IEEE_FLOAT          (0x0003)
+#define WAVE_FORMAT_ALAW                (0x0006)
+#define WAVE_FORMAT_MULAW               (0x0007)
+#define WAVE_FORMAT_OKI_ADPCM           (0x0010)
+#define WAVE_FORMAT_IMA_ADPCM           (0x0011)
+#define WAVE_FORMAT_DIGISTD             (0x0015)
+#define WAVE_FORMAT_DIGIFIX             (0x0016)
+#define WAVE_FORMAT_DOLBY_AC2           (0x0030)
+#define WAVE_FORMAT_GSM610              (0x0031)
+#define WAVE_FORMAT_ROCKWELL_ADPCM      (0x003b)
+#define WAVE_FORMAT_ROCKWELL_DIGITALK   (0x003c)
+#define WAVE_FORMAT_G721_ADPCM          (0x0040)
+#define WAVE_FORMAT_G728_CELP           (0x0041)
+#define WAVE_FORMAT_MPEG                (0x0050)
+#define WAVE_FORMAT_MPEGLAYER3          (0x0055)
+#define WAVE_FORMAT_G726_ADPCM          (0x0064)
+#define WAVE_FORMAT_G722_ADPCM          (0x0065)
+
+#define CD_BLOCK_SIZE                   (2352)
+#define CD_BLOCKS_PER_SEC               (75)
+#define CD_MIN_BURNABLE_SIZE            (705600)
+#define CD_CHANNELS                     (2)
+#define CD_SAMPLES_PER_SEC              (44100)
+#define CD_BITS_PER_SAMPLE              (16)
+#define CD_RATE                         (176400)
+
+#define CANONICAL_HEADER_SIZE           (44)
+
+#define PROBLEM_NOT_CD_QUALITY          (0x00000001)
+#define PROBLEM_CD_BUT_BAD_BOUND        (0x00000002)
+#define PROBLEM_CD_BUT_TOO_SHORT        (0x00000004)
+#define PROBLEM_HEADER_NOT_CANONICAL    (0x00000008)
+#define PROBLEM_EXTRA_CHUNKS            (0x00000010)
+#define PROBLEM_HEADER_INCONSISTENT     (0x00000020)
+
+#define PROB_NOT_CD(f)                  ((f.problems) & (PROBLEM_NOT_CD_QUALITY))
+#define PROB_BAD_BOUND(f)               ((f.problems) & (PROBLEM_CD_BUT_BAD_BOUND))
+#define PROB_TOO_SHORT(f)               ((f.problems) & (PROBLEM_CD_BUT_TOO_SHORT))
+#define PROB_HDR_NOT_CANONICAL(f)       ((f.problems) & (PROBLEM_HEADER_NOT_CANONICAL))
+#define PROB_EXTRA_CHUNKS(f)            ((f.problems) & (PROBLEM_EXTRA_CHUNKS))
+#define PROB_HDR_INCONSISTENT(f)        ((f.problems) & (PROBLEM_HEADER_INCONSISTENT))
+
+typedef struct _shn_config
+{
+	gint      error_output_method;
+	gchar    *error_output_method_config_name;
+	gchar    *seek_tables_path;
+	gchar    *seek_tables_path_config_name;
+	gchar    *relative_seek_tables_path;
+	gchar    *relative_seek_tables_path_config_name;
+	gboolean  verbose;
+	gchar    *verbose_config_name;
+	gboolean  swap_bytes;
+	gchar    *swap_bytes_config_name;
+	gboolean  load_textfiles;
+	gchar	 *load_textfiles_config_name;
+	gchar	 *textfile_extensions;
+	gchar	 *textfile_extensions_config_name;
+} shn_config;
+
+typedef struct _shn_decode_state
+{
+	uchar *getbuf;
+	uchar *getbufp;
+	int    nbitget;
+	int    nbyteget;
+	ulong  gbuffer;
+	schar *writebuf;
+	schar *writefub;
+	int    nwritebuf;
+} shn_decode_state;
+
+typedef struct _shn_seek_header
+{
+	uchar data[SEEK_HEADER_SIZE];
+	slong version;
+	ulong shnFileSize;	
+} shn_seek_header;
+
+typedef struct _shn_seek_trailer
+{
+	uchar data[SEEK_TRAILER_SIZE];
+	ulong seekTableSize;
+} shn_seek_trailer;
+
+typedef struct _shn_seek_entry
+{
+	uchar data[SEEK_ENTRY_SIZE];
+} shn_seek_entry;
+
+/* old way, kept for reference.
+   (changed because some compilers apparently don't support #pragma pack(1))
+
+typedef struct _shn_seek_header
+{
+	char signature[4];
+	unsigned long version;
+	unsigned long shnFileSize;
+} shn_seek_header;
+
+typedef struct _shn_seek_trailer
+{
+	unsigned long seekTableSize;
+	char signature[8];
+} shn_seek_trailer;
+
+typedef struct _shn_seek_entry
+{
+	unsigned long  shnSample;
+	unsigned long  shnByteOffset;
+	unsigned long  shnLastPosition;
+	unsigned short shnByteGet;
+	unsigned short shnBufferOffset;
+	unsigned short shnBitOffset;
+	unsigned long  shnGBuffer;
+	unsigned short shnBitShift;
+	long cbuf0[3];
+	long cbuf1[3];
+	long offset0[4];
+	long offset1[4];
+} shn_seek_entry;
+*/
+
+typedef struct _shn_wave_header
+{
+	char *filename,
+	      m_ss[16];
+
+	uint header_size;
+
+	ushort channels,
+	       block_align,
+	       bits_per_sample,
+	       wave_format;
+
+	ulong samples_per_sec,
+	      avg_bytes_per_sec,
+	      rate,
+	      length,
+	      data_size,
+	      total_size,
+	      chunk_size,
+	      actual_size;
+
+	double exact_length;
+
+	int   file_has_id3v2_tag;
+	long  id3v2_tag_size;
+
+	ulong problems;
+} shn_wave_header;
+
+typedef struct _shn_vars
+{
+	VFSFile *fd;
+	int    seek_to;
+	int    eof;
+	int    going;
+	slong  seek_table_entries;
+	ulong  seek_resolution;
+	int    bytes_in_buf;
+	uchar  buffer[OUT_BUFFER_SIZE];
+	int    bytes_in_header;
+	uchar  header[OUT_BUFFER_SIZE];
+	int    fatal_error;
+	schar  fatal_error_msg[BUF_SIZE];
+	int    reading_function_code;
+	ulong  last_file_position;
+	ulong  last_file_position_no_really;
+	ulong  initial_file_position;
+	ulong  bytes_read;
+	unsigned short actual_bitshift;
+	int    actual_maxnlpc;
+	int    actual_nmean;
+	int    actual_nchan;
+	long   seek_offset;
+	InputPlayback *playback;
+} shn_vars;
+
+typedef struct _shn_file
+{
+	shn_vars          vars;
+	shn_decode_state *decode_state;
+	shn_wave_header   wave_header;
+	shn_seek_header   seek_header;
+	shn_seek_trailer  seek_trailer;
+	shn_seek_entry   *seek_table;
+} shn_file;
+
+extern InputPlugin shn_ip;
+extern shn_file *shnfile;
+extern shn_config shn_cfg;
+
+extern shn_seek_entry *shn_seek_entry_search(shn_seek_entry *,ulong,ulong,ulong,ulong);
+extern void shn_load_seek_table(shn_file *,char *);
+extern void shn_unload(shn_file *);
+extern void shn_display_about(void);
+extern void shn_display_configure(void);
+extern void shn_display_info(shn_file *);
+extern int shn_verify_header(shn_file *);
+extern int shn_filename_contains_a_dot(char *);
+extern char *shn_get_base_filename(char *);
+extern char *shn_get_base_directory(char *);
+extern void shn_length_to_str(shn_file *);
+extern ulong shn_uchar_to_ulong_le(uchar *);
+extern slong shn_uchar_to_slong_le(uchar *);
+extern ushort shn_uchar_to_ushort_le(uchar *);
+extern char *shn_format_to_str(ushort);
+extern void shn_message_box(char *);
+extern void shn_debug(char *, ...);
+extern void shn_error(char *, ...);
+extern void shn_error_fatal(shn_file *,char *, ...);
+extern void shn_snprintf(char *,int,char *, ...);
+extern VFSFile *shn_open_and_discard_id3v2_tag(char *,int *,long *);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/shorten.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,54 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright (C) 1992-1995 Tony Robinson                                      *
+*                                                                             *
+*  See the file doc/LICENSE.shorten for conditions on distribution and usage  *
+*                                                                             *
+******************************************************************************/
+
+/*
+ * $Id: shorten.c,v 1.7 2003/08/26 05:34:04 jason Exp $
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <setjmp.h>
+#include "shorten.h"
+
+void init_offset(slong **offset,int nchan,int nblock,int ftype)
+{
+  slong mean = 0;
+  int  chan, i;
+
+  /* initialise offset */
+  switch(ftype)
+  {
+  	case TYPE_AU1:
+  	case TYPE_S8:
+  	case TYPE_S16HL:
+  	case TYPE_S16LH:
+  	case TYPE_ULAW:
+  	case TYPE_AU2:
+  	case TYPE_AU3:
+  	case TYPE_ALAW:
+    	mean = 0;
+    	break;
+  	case TYPE_U8:
+    	mean = 0x80;
+    	break;
+  	case TYPE_U16HL:
+  	case TYPE_U16LH:
+    	mean = 0x8000;
+    	break;
+  	default:
+        shn_debug("Unknown file type: %d", ftype);
+  }
+
+  for(chan = 0; chan < nchan; chan++)
+    for(i = 0; i < nblock; i++)
+      offset[chan][i] = mean;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/shorten.h	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,222 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright (C) 1992-1995 Tony Robinson                                      *
+*                                                                             *
+*  See the file doc/LICENSE.shorten for conditions on distribution and usage  *
+*                                                                             *
+******************************************************************************/
+
+/*
+ * $Id: shorten.h,v 1.4 2001/12/30 05:12:04 jason Exp $
+ */
+
+#ifndef _SHORTEN_H
+#define _SHORTEN_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+#else
+#  if SIZEOF_UNSIGNED_LONG == 4
+#    define uint32_t unsigned long
+#    define int32_t long
+#  else
+#    define uint32_t unsigned int
+#    define int32_t int
+#  endif
+#  define uint16_t unsigned short
+#  define uint8_t unsigned char
+#  define int16_t short
+#  define int8_t char
+#endif
+
+#undef  ulong
+#undef  ushort
+#undef  uchar
+#undef  slong
+#undef  sshort
+#undef  schar
+#define ulong   uint32_t
+#define ushort  uint16_t
+#define uchar   uint8_t
+#define slong   int32_t
+#define sshort  int16_t
+#define schar   int8_t
+
+#include "shn.h"
+
+extern shn_file *shnfile;
+
+#define MAGIC			"ajkg"
+#define FORMAT_VERSION		2
+#define MIN_SUPPORTED_VERSION	1
+#define MAX_SUPPORTED_VERSION	3
+#define MAX_VERSION		7
+
+#define UNDEFINED_UINT		-1
+#define DEFAULT_BLOCK_SIZE	256
+#define DEFAULT_V0NMEAN	0
+#define DEFAULT_V2NMEAN	4
+#define DEFAULT_MAXNLPC	0
+#define DEFAULT_NCHAN		1
+#define DEFAULT_NSKIP		0
+#define DEFAULT_NDISCARD	0
+#define NBITPERLONG		32
+#define DEFAULT_MINSNR          256
+#define DEFAULT_MAXRESNSTR	"32.0"
+#define DEFAULT_QUANTERROR	0
+#define MINBITRATE		2.5
+
+#define MAX_LPC_ORDER	64
+#define CHANSIZE	0
+#define ENERGYSIZE	3
+#define BITSHIFTSIZE	2
+#define NWRAP		3
+
+#define FNSIZE		2
+#define FN_DIFF0	0
+#define FN_DIFF1	1
+#define FN_DIFF2	2
+#define FN_DIFF3	3
+#define FN_QUIT		4
+#define FN_BLOCKSIZE	5
+#define FN_BITSHIFT	6
+#define FN_QLPC		7
+#define FN_ZERO		8
+#define FN_VERBATIM     9
+
+#define VERBATIM_CKSIZE_SIZE 5	/* a var_put code size */
+#define VERBATIM_BYTE_SIZE 8	/* code size 8 on single bytes means
+				 * no compression at all */
+#define VERBATIM_CHUNK_MAX 256	/* max. size of a FN_VERBATIM chunk */
+
+#define ULONGSIZE	2
+#define NSKIPSIZE	1
+#define LPCQSIZE	2
+#define LPCQUANT	5
+#define XBYTESIZE	7
+
+#define TYPESIZE	4
+#define TYPE_AU1	0	/* original lossless ulaw                    */
+#define TYPE_S8	        1	/* signed 8 bit characters                   */
+#define TYPE_U8         2	/* unsigned 8 bit characters                 */
+#define TYPE_S16HL	3	/* signed 16 bit shorts: high-low            */
+#define TYPE_U16HL	4	/* unsigned 16 bit shorts: high-low          */
+#define TYPE_S16LH	5	/* signed 16 bit shorts: low-high            */
+#define TYPE_U16LH	6	/* unsigned 16 bit shorts: low-high          */
+#define TYPE_ULAW	7	/* lossy ulaw: internal conversion to linear */
+#define TYPE_AU2	8	/* new ulaw with zero mapping                */
+#define TYPE_AU3	9	/* lossless alaw                             */
+#define TYPE_ALAW 	10	/* lossy alaw: internal conversion to linear */
+#define TYPE_RIFF_WAVE  11	/* Microsoft .WAV files                      */
+#define TYPE_EOF	12
+#define TYPE_GENERIC_ULAW 128
+#define TYPE_GENERIC_ALAW 129
+
+#define POSITIVE_ULAW_ZERO 0xff
+#define NEGATIVE_ULAW_ZERO 0x7f
+
+#ifndef MAX_PATH
+#define MAX_PATH 2048
+#endif
+
+#ifndef	MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef	MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#if defined(unix) && !defined(linux)
+#define labs abs
+#endif
+
+#define ROUNDEDSHIFTDOWN(x, n) (((n) == 0) ? (x) : ((x) >> ((n) - 1)) >> 1)
+
+#ifndef M_LN2
+#define	M_LN2	0.69314718055994530942
+#endif
+
+#ifndef M_PI
+#define M_PI	3.14159265358979323846
+#endif
+
+/* BUFSIZ must be a multiple of four to contain a whole number of words */
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+
+#define BUFSIZ 512
+
+#define V2LPCQOFFSET (1 << LPCQUANT);
+
+#define UINT_GET(nbit, shnfile) \
+  ((version == 0) ? uvar_get(nbit, shnfile) : ulong_get(shnfile))
+
+#define putc_exit(val, stream)\
+{ char rval;\
+  if((rval = putc((val), (stream))) != (char) (val))\
+    complain("FATALERROR: write failed: putc returns EOF");\
+}
+
+extern int getc_exit_val;
+#define getc_exit(stream)\
+(((getc_exit_val = vfs_getc(stream)) == EOF) ? \
+  complain("FATALERROR: read failed: getc returns EOF"), 0: getc_exit_val)
+
+/************************/
+/* defined in shorten.c */
+extern void	init_offset(slong**, int, int, int);
+extern int	shorten(FILE*, FILE*, int, char**);
+
+/**************************/
+/* defined in Sulawalaw.c */
+extern int Sulaw2lineartab[];
+#define Sulaw2linear(i) (Sulaw2lineartab[i])
+#ifndef Sulaw2linear
+extern int	Sulaw2linear(uchar);
+#endif
+extern uchar	Slinear2ulaw(int);
+
+extern int Salaw2lineartab[];
+#define Salaw2linear(i) (Salaw2lineartab[i])
+#ifndef Salaw2linear
+extern int	Salaw2linear(uchar);
+#endif
+extern uchar	Slinear2alaw(int);
+
+/**********************/
+/* defined in fixio.c */
+extern void	init_sizeof_sample(void);
+extern void     fwrite_type_init(shn_file*);
+extern void     fwrite_type(slong**,int,int,int,shn_file*);
+extern void     fwrite_type_quit(shn_file*);
+extern void	fix_bitshift(slong*, int, int, int);
+
+/**********************/
+/* defined in vario.c */
+extern void	var_get_init(shn_file*);
+extern slong	uvar_get(int, shn_file*);
+extern slong	var_get(int, shn_file*);
+extern ulong	ulong_get(shn_file*);
+extern void	var_get_quit(shn_file*);
+
+extern int	sizeof_uvar(ulong, int);
+extern int	sizeof_var(slong, int);
+
+extern void	mkmasktab(void);
+extern ulong	word_get(shn_file*);
+
+/**********************/
+/* defined in array.c */
+extern void* 	pmalloc(ulong, shn_file*);
+extern slong**	long2d(ulong, ulong, shn_file*);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/sulawalaw.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,192 @@
+/*
+ * $Id: sulawalaw.c,v 1.5 2001/12/30 05:12:04 jason Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+#include "shorten.h"
+
+int Sulaw2lineartab[] = {-32124, -31100, -30076, -29052, -28028, -27004,
+  -25980, -24956, -23932, -22908, -21884, -20860, -19836, -18812,
+  -17788, -16764, -15996, -15484, -14972, -14460, -13948, -13436,
+  -12924, -12412, -11900, -11388, -10876, -10364, -9852, -9340, -8828,
+  -8316, -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884,
+  -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900, -3772, -3644,
+  -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364,
+  -2236, -2108, -1980, -1884, -1820, -1756, -1692, -1628, -1564, -1500,
+  -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876,
+  -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524,
+  -492, -460, -428, -396, -372, -356, -340, -324, -308, -292, -276,
+  -260, -244, -228, -212, -196, -180, -164, -148, -132, -120, -112,
+  -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0,
+  32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908,
+  21884, 20860, 19836, 18812, 17788, 16764, 15996, 15484, 14972, 14460,
+  13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340,
+  8828, 8316, 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884,
+  5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900, 3772, 3644, 3516,
+  3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108,
+  1980, 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308,
+  1244, 1180, 1116, 1052, 988, 924, 876, 844, 812, 780, 748, 716, 684,
+  652, 620, 588, 556, 524, 492, 460, 428, 396, 372, 356, 340, 324, 308,
+  292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104,
+  96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0};
+
+#ifndef Sulaw2linear
+#ifdef __STDC__
+int Sulaw2linear(uchar ulaw) {
+#else
+int Sulaw2linear(ulaw) uchar ulaw; {
+#endif
+  return(Sulaw2lineartab[ulaw]);
+}
+#endif
+
+/* adapted by ajr for int input */
+#ifdef __STDC__
+uchar Slinear2ulaw(int sample) {
+#else
+uchar Slinear2ulaw(sample) int sample; {
+#endif
+/*
+** This routine converts from linear to ulaw.
+**
+** Craig Reese: IDA/Supercomputing Research Center
+** Joe Campbell: Department of Defense
+** 29 September 1989
+**
+** References:
+** 1) CCITT Recommendation G.711  (very difficult to follow)
+** 2) "A New Digital Technique for Implementation of Any
+**     Continuous PCM Companding Law," Villeret, Michel,
+**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
+**     1973, pg. 11.12-11.17
+** 3) MIL-STD-188-113,"Interoperability and Performance Standards
+**     for Analog-to_Digital Conversion Techniques,"
+**     17 February 1987
+**
+** Input: Signed 16 bit linear sample
+** Output: 8 bit ulaw sample
+*/
+
+#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+  static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+                             4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+                             5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+                             5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+                             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                             6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+                             7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
+  int sign, exponent, mantissa;
+  uchar ulawbyte;
+
+  /* Get the sample into sign-magnitude. */
+  if(sample < 0) {
+    sign   = 0x80;
+    sample = -sample;
+  }
+  else
+    sign = 0;
+
+  /* clip the magnitude */
+  if(sample > CLIP) sample = CLIP;
+
+  /* Convert from 16 bit linear to ulaw. */
+  sample = sample + BIAS;
+  exponent = exp_lut[( sample >> 7 ) & 0xFF];
+  mantissa = (sample >> (exponent + 3)) & 0x0F;
+  ulawbyte = ~(sign | (exponent << 4) | mantissa);
+
+  return(ulawbyte);
+}
+
+
+/******************
+ * ALAW starts here
+ */
+
+int Salaw2lineartab[] = {-5504, -5248, -6016, -5760, -4480, -4224,
+  -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+  -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648,
+  -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064,
+  -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256,
+  -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032,
+  -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616,
+  -13056, -12544, -14080, -13568, -344, -328, -376, -360, -280, -264,
+  -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72,
+  -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136,
+  -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+  -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656,
+  -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816,
+  -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
+  7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008,
+  2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136,
+  3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+  30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496,
+  12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616,
+  13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296,
+  472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56,
+  40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440,
+  1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760,
+  1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976,
+  816, 784, 880, 848};
+
+#ifndef Salaw2linear
+#ifdef __STDC__
+int Salaw2linear(uchar alaw) {
+#else
+int Salaw2linear(alaw) uchar alaw; {
+#endif
+  return(Salaw2lineartab[alaw]);
+}
+#endif
+
+/* this is derived from the Sun code - it is a bit simpler and has int input */
+#define QUANT_MASK      (0xf)           /* Quantization field mask. */
+#define NSEGS           (8)             /* Number of A-law segments. */
+#define SEG_SHIFT       (4)             /* Left shift for segment number. */
+#ifdef __STDC__
+uchar Slinear2alaw(int linear) {
+#else
+uchar Slinear2alaw(linear) int linear; {
+#endif
+  int	seg;
+  uchar aval, mask;
+  static sshort seg_aend[NSEGS] = {0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,0x7ff,0xfff};
+
+  linear = linear >> 3;
+
+  if(linear >= 0) {
+    mask = 0xd5;		/* sign (7th) bit = 1 */
+  } else {
+    mask = 0x55;		/* sign bit = 0 */
+    linear = -linear - 1;
+  }
+
+  /* Convert the scaled magnitude to segment number. */
+  for(seg = 0; seg < NSEGS && linear > seg_aend[seg]; seg++);
+
+  /* Combine the sign, segment, and quantization bits. */
+  if(seg >= NSEGS)		/* out of range, return maximum value. */
+    return (uchar) (0x7F ^ mask);
+  else {
+    aval = (uchar) seg << SEG_SHIFT;
+    if (seg < 2)
+      aval |= (linear >> 1) & QUANT_MASK;
+    else
+      aval |= (linear >> seg) & QUANT_MASK;
+    return (aval ^ mask);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/vario.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,146 @@
+/******************************************************************************
+*                                                                             *
+*  Copyright (C) 1992-1995 Tony Robinson                                      *
+*                                                                             *
+*  See the file doc/LICENSE.shorten for conditions on distribution and usage  *
+*                                                                             *
+******************************************************************************/
+
+/*
+ * $Id: vario.c,v 1.10 2004/05/04 02:26:36 jason Exp $
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "shorten.h"
+
+#define MASKTABSIZE 33
+ulong masktab[MASKTABSIZE];
+
+void mkmasktab() {
+  int i;
+  ulong val = 0;
+
+  masktab[0] = val;
+  for(i = 1; i < MASKTABSIZE; i++) {
+    val <<= 1;
+    val |= 1;
+    masktab[i] = val;
+  }
+}
+
+void var_get_init(shn_file *this_shn)
+{
+  mkmasktab();
+
+  this_shn->decode_state->getbuf   = (uchar*) pmalloc((ulong) BUFSIZ,this_shn);
+  this_shn->decode_state->getbufp  = this_shn->decode_state->getbuf;
+  this_shn->decode_state->nbyteget = 0;
+  this_shn->decode_state->gbuffer  = 0;
+  this_shn->decode_state->nbitget  = 0;
+}
+
+ulong word_get(shn_file *this_shn)
+{
+  ulong buffer;
+  int bytes;
+
+  if(this_shn->decode_state->nbyteget < 4)
+  {
+    this_shn->vars.last_file_position = this_shn->vars.bytes_read;
+
+    bytes = vfs_fread((uchar*) this_shn->decode_state->getbuf, 1, BUFSIZ, this_shn->vars.fd);
+    this_shn->decode_state->nbyteget += bytes;
+
+    if(this_shn->decode_state->nbyteget < 4) {
+      shn_error_fatal(this_shn,"Premature EOF on compressed stream -\npossible corrupt or truncated file");
+      return (ulong)0;
+    }
+
+    this_shn->vars.bytes_read += bytes;
+
+    this_shn->decode_state->getbufp = this_shn->decode_state->getbuf;
+  }
+
+  buffer = (((slong) (this_shn->decode_state->getbufp[0])) << 24) | (((slong) (this_shn->decode_state->getbufp[1])) << 16) |
+    (((slong) (this_shn->decode_state->getbufp[2])) <<  8) | ((slong) (this_shn->decode_state->getbufp[3]));
+
+  this_shn->decode_state->getbufp += 4;
+  this_shn->decode_state->nbyteget -= 4;
+
+  return(buffer);
+}
+
+slong uvar_get(int nbin,shn_file *this_shn)
+{
+  slong result;
+
+  if (this_shn->vars.reading_function_code) {
+    this_shn->vars.last_file_position_no_really = this_shn->vars.last_file_position;
+  }
+
+  if(this_shn->decode_state->nbitget == 0)
+  {
+    this_shn->decode_state->gbuffer = word_get(this_shn);
+    if (this_shn->vars.fatal_error)
+      return (ulong)0;
+    this_shn->decode_state->nbitget = 32;
+  }
+
+  for(result = 0; !(this_shn->decode_state->gbuffer & (1L << --(this_shn->decode_state->nbitget))); result++)
+  {
+    if(this_shn->decode_state->nbitget == 0)
+    {
+      this_shn->decode_state->gbuffer = word_get(this_shn);
+      if (this_shn->vars.fatal_error)
+        return (ulong)0;
+      this_shn->decode_state->nbitget = 32;
+    }
+  }
+
+  while(nbin != 0)
+  {
+    if(this_shn->decode_state->nbitget >= nbin)
+    {
+      result = (result << nbin) | ((this_shn->decode_state->gbuffer >> (this_shn->decode_state->nbitget-nbin)) &masktab[nbin]);
+      this_shn->decode_state->nbitget -= nbin;
+      nbin = 0;
+    }
+    else
+    {
+      result = (result << this_shn->decode_state->nbitget) | (this_shn->decode_state->gbuffer & masktab[this_shn->decode_state->nbitget]);
+      this_shn->decode_state->gbuffer = word_get(this_shn);
+      if (this_shn->vars.fatal_error)
+        return (ulong)0;
+      nbin -= this_shn->decode_state->nbitget;
+      this_shn->decode_state->nbitget = 32;
+    }
+  }
+
+  return(result);
+}
+
+ulong ulong_get(shn_file *this_shn)
+{
+  unsigned int nbit = uvar_get(ULONGSIZE,this_shn);
+  if (this_shn->vars.fatal_error)
+    return (ulong)0;
+  return(uvar_get(nbit,this_shn));
+}
+
+slong var_get(int nbin,shn_file *this_shn)
+{
+  ulong uvar = uvar_get(nbin + 1,this_shn);
+  if (this_shn->vars.fatal_error)
+    return (slong)0;
+
+  if(uvar & 1) return((slong) ~(uvar >> 1));
+  else return((slong) (uvar >> 1));
+}
+
+void var_get_quit(shn_file *this_shn)
+{
+  free((void *) this_shn->decode_state->getbuf);
+  this_shn->decode_state->getbuf = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shnplug/wave.c	Fri Jul 20 10:29:54 2007 -0500
@@ -0,0 +1,268 @@
+/*  wave.c - functions to parse and verify WAVE headers
+ *  Copyright (C) 2000-2007  Jason Jordan <shnutils@freeshell.org>
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * $Id: wave.c,v 1.13 2007/03/23 05:49:48 jason Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include "shorten.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+int is_valid_file(shn_file *info)
+/* determines whether the given filename (info->filename) is a regular file, and is readable */
+{
+  struct stat sz;
+  FILE *f;
+
+  if (0 != stat(info->wave_header.filename,&sz)) {
+    if (errno == ENOENT)
+      shn_error("cannot open '%s' because it does not exist",info->wave_header.filename);
+    else if (errno == EACCES)
+      shn_error("cannot open '%s' due to insufficient permissions",info->wave_header.filename);
+    else if (errno == EFAULT)
+      shn_error("cannot open '%s' due to bad address",info->wave_header.filename);
+    else if (errno == ENOMEM)
+      shn_error("cannot open '%s' because the kernel ran out of memory",info->wave_header.filename);
+    else if (errno == ENAMETOOLONG)
+      shn_error("cannot open '%s' because the file name is too long",info->wave_header.filename);
+    else
+      shn_error("cannot open '%s' due to an unknown problem",info->wave_header.filename);
+    return 0;
+  }
+  if (0 == S_ISREG(sz.st_mode)) {
+    if (S_ISLNK(sz.st_mode))
+      shn_error("'%s' is a symbolic link, not a regular file",info->wave_header.filename);
+    else if (S_ISDIR(sz.st_mode))
+      shn_error("'%s' is a directory, not a regular file",info->wave_header.filename);
+    else if (S_ISCHR(sz.st_mode))
+      shn_error("'%s' is a character device, not a regular file",info->wave_header.filename);
+    else if (S_ISBLK(sz.st_mode))
+      shn_error("'%s' is a block device, not a regular file",info->wave_header.filename);
+    else if (S_ISFIFO(sz.st_mode))
+      shn_error("'%s' is a fifo, not a regular file",info->wave_header.filename);
+    else if (S_ISSOCK(sz.st_mode))
+      shn_error("'%s' is a socket, not a regular file",info->wave_header.filename);
+    return 0;
+  }
+  info->wave_header.actual_size = (ulong)sz.st_size;
+
+  if (NULL == (f = fopen(info->wave_header.filename,"rb"))) {
+    shn_error("could not open '%s': %s",info->wave_header.filename,strerror(errno));
+    return 0;
+  }
+  fclose(f);
+
+  return 1;
+}
+
+int shn_verify_header(shn_file *this_shn)
+{
+	ulong l;
+	int cur = 0;
+
+	if (0 == is_valid_file(this_shn))
+	{
+		shn_debug("while processing '%s': something went wrong while opening this file, see above",this_shn->wave_header.filename);
+		return 0;
+	}
+
+	if (this_shn->vars.bytes_in_header < CANONICAL_HEADER_SIZE) {
+		shn_debug("while processing '%s': header is only %d bytes (should be at least %d bytes)",
+			this_shn->wave_header.filename,this_shn->vars.bytes_in_header,CANONICAL_HEADER_SIZE);
+		return 0;
+	}
+
+	if (WAVE_RIFF != shn_uchar_to_ulong_le(this_shn->vars.header+cur))
+	{
+		if (AIFF_FORM == shn_uchar_to_ulong_le(this_shn->vars.header+cur))
+			shn_debug("while processing '%s': file contains AIFF data, which is currently not supported",this_shn->wave_header.filename);
+		else
+			shn_debug("while processing '%s': WAVE header is missing RIFF tag - possible corrupt file",this_shn->wave_header.filename);
+		return 0;
+	}
+	cur += 4;
+
+	this_shn->wave_header.chunk_size = shn_uchar_to_ulong_le(this_shn->vars.header+cur);
+	cur += 4;
+
+	if (WAVE_WAVE != shn_uchar_to_ulong_le(this_shn->vars.header+cur))
+	{
+		shn_debug("while processing '%s': WAVE header is missing WAVE tag",this_shn->wave_header.filename);
+		return 0;
+	}
+	cur += 4;
+
+	for (;;)
+	{
+		cur += 4;
+
+		l = shn_uchar_to_ulong_le(this_shn->vars.header+cur);
+		cur += 4;
+
+		if (WAVE_FMT == shn_uchar_to_ulong_le(this_shn->vars.header+cur-8))
+			break;
+
+		cur += l;
+	}
+
+	if (l < 16)
+	{
+		shn_debug("while processing '%s': fmt chunk in WAVE header was too short",this_shn->wave_header.filename);
+		return 0;
+	}
+
+	this_shn->wave_header.wave_format = shn_uchar_to_ushort_le(this_shn->vars.header+cur);
+	cur += 2;
+
+	switch (this_shn->wave_header.wave_format)
+	{
+		case WAVE_FORMAT_PCM:
+			break;
+		default:
+			shn_debug("while processing '%s': unsupported format 0x%04x (%s) - only PCM data is supported at this time",
+				this_shn->wave_header.filename,this_shn->wave_header.wave_format,shn_format_to_str(this_shn->wave_header.wave_format));
+                        return 0;
+	}
+
+	this_shn->wave_header.channels = shn_uchar_to_ushort_le(this_shn->vars.header+cur);
+	cur += 2;
+	this_shn->wave_header.samples_per_sec = shn_uchar_to_ulong_le(this_shn->vars.header+cur);
+	cur += 4;
+	this_shn->wave_header.avg_bytes_per_sec = shn_uchar_to_ulong_le(this_shn->vars.header+cur);
+	cur += 4;
+	this_shn->wave_header.block_align = shn_uchar_to_ushort_le(this_shn->vars.header+cur);
+	cur += 2;
+	this_shn->wave_header.bits_per_sample = shn_uchar_to_ushort_le(this_shn->vars.header+cur);
+	cur += 2;
+
+	if (this_shn->wave_header.bits_per_sample != 8 && this_shn->wave_header.bits_per_sample != 16)
+	{
+		shn_debug("while processing '%s': bits per sample is neither 8 nor 16",this_shn->wave_header.filename);
+		return 0;
+	}
+
+	l -= 16;
+
+	if (l > 0)
+		cur += l;
+
+	for (;;)
+	{
+		cur += 4;
+
+		l = shn_uchar_to_ulong_le(this_shn->vars.header+cur);
+		cur += 4;
+
+		if (WAVE_DATA == shn_uchar_to_ulong_le(this_shn->vars.header+cur-8))
+			break;
+
+		cur += l;
+	}
+
+	this_shn->wave_header.rate = ((uint)this_shn->wave_header.samples_per_sec *
+				      (uint)this_shn->wave_header.channels *
+				      (uint)this_shn->wave_header.bits_per_sample) / 8;
+	this_shn->wave_header.header_size = cur;
+	this_shn->wave_header.data_size = l;
+	this_shn->wave_header.total_size = this_shn->wave_header.chunk_size + 8;
+	this_shn->wave_header.length = this_shn->wave_header.data_size / this_shn->wave_header.rate;
+	this_shn->wave_header.exact_length = (double)this_shn->wave_header.data_size / (double)this_shn->wave_header.rate;
+
+	if (this_shn->wave_header.channels == CD_CHANNELS &&
+	    this_shn->wave_header.bits_per_sample == CD_BITS_PER_SAMPLE &&
+	    this_shn->wave_header.samples_per_sec == CD_SAMPLES_PER_SEC &&
+	    this_shn->wave_header.avg_bytes_per_sec == CD_RATE &&
+	    this_shn->wave_header.rate == CD_RATE)
+	{
+		if (this_shn->wave_header.data_size < CD_MIN_BURNABLE_SIZE)
+			this_shn->wave_header.problems |= PROBLEM_CD_BUT_TOO_SHORT;
+		if (this_shn->wave_header.data_size % CD_BLOCK_SIZE != 0)
+			this_shn->wave_header.problems |= PROBLEM_CD_BUT_BAD_BOUND;
+	}
+	else
+		this_shn->wave_header.problems |= PROBLEM_NOT_CD_QUALITY;
+
+	if (this_shn->wave_header.header_size != CANONICAL_HEADER_SIZE)
+		this_shn->wave_header.problems |= PROBLEM_HEADER_NOT_CANONICAL;
+
+	if ((ulong)this_shn->wave_header.header_size + this_shn->wave_header.data_size > this_shn->wave_header.total_size)
+		this_shn->wave_header.problems |= PROBLEM_HEADER_INCONSISTENT;
+
+	if ((ulong)this_shn->wave_header.header_size + this_shn->wave_header.data_size < this_shn->wave_header.total_size)
+		this_shn->wave_header.problems |= PROBLEM_EXTRA_CHUNKS;
+
+	shn_length_to_str(this_shn);
+
+	/* header looks ok */
+	return 1;
+}
+
+char *shn_format_to_str(ushort format)
+{
+  switch (format) {
+    case WAVE_FORMAT_UNKNOWN:
+      return "Microsoft Official Unknown";
+    case WAVE_FORMAT_PCM:
+      return "Microsoft PCM";
+    case WAVE_FORMAT_ADPCM:
+      return "Microsoft ADPCM";
+    case WAVE_FORMAT_IEEE_FLOAT:
+      return "IEEE Float";
+    case WAVE_FORMAT_ALAW:
+      return "Microsoft A-law";
+    case WAVE_FORMAT_MULAW:
+      return "Microsoft U-law";
+    case WAVE_FORMAT_OKI_ADPCM:
+      return "OKI ADPCM format";
+    case WAVE_FORMAT_IMA_ADPCM:
+      return "IMA ADPCM";
+    case WAVE_FORMAT_DIGISTD:
+      return "Digistd format";
+    case WAVE_FORMAT_DIGIFIX:
+      return "Digifix format";
+    case WAVE_FORMAT_DOLBY_AC2:
+      return "Dolby AC2";
+    case WAVE_FORMAT_GSM610:
+      return "GSM 6.10";
+    case WAVE_FORMAT_ROCKWELL_ADPCM:
+      return "Rockwell ADPCM";
+    case WAVE_FORMAT_ROCKWELL_DIGITALK:
+      return "Rockwell DIGITALK";
+    case WAVE_FORMAT_G721_ADPCM:
+      return "G.721 ADPCM";
+    case WAVE_FORMAT_G728_CELP:
+      return "G.728 CELP";
+    case WAVE_FORMAT_MPEG:
+      return "MPEG";
+    case WAVE_FORMAT_MPEGLAYER3:
+      return "MPEG Layer 3";
+    case WAVE_FORMAT_G726_ADPCM:
+      return "G.726 ADPCM";
+    case WAVE_FORMAT_G722_ADPCM:
+      return "G.722 ADPCM";
+  }
+  return "Unknown";
+}