shntool 1.2.x tutorial
----------------------

This is a fairly brief but hopefully useful document on how to use shntool and
its various modes.  It is a work in progress, so take what it says with a grain
of salt.  I will try to keep it current with each new release.  However, even if
this document becomes dated, shntool's built-in help screens as well as its man
page (i.e. the README.txt for Windows folks) will be kept current, so if you
have any troubles you can consult those sources of information.  The help
screens can be accessed from any mode by giving the '-h' command-line switch.

NOTE: For the purposes of this tutorial, all sample commands will be given in
their long form (e.g. 'shntool len' as opposed to 'shnlen'), since some
platforms do not support symbolic links, which allow one to use the short form.
Also, the '%' represents the command prompt, whatever platform you are on.
Most of you know this, but this is for those who don't, so that I don't get any
email saying "When I run '% shntool', it says 'command not found'!!!!"  :^)

shntool's modes can generally be split into three categories - modes that simply
display information about given files, modes that create new files based on
input files, and modes that do something else that is not covered by the above
two categories.


Contents:

1. Modes that display information
  1a. len mode
  1b. info mode
  1c. md5 mode
2. Modes that create files
  2a. fix mode
  2b. join mode
  2c. split mode
  2d. strip mode
  2e. conv mode
3. Miscellaneous modes
  3a. cat mode
  3b. cmp mode
4. Custom format modules
  4a. cust format


=================================
1. Modes that display information
=================================

Currently len, info and md5 modes are the only modes that just show information
about files.  All of these modes read filenames from the command line, or from
standard input if none are given on the command line.


------------
1a. len mode
------------

len mode shows a one-line summary of many properties of a given file.  Below is
sample output from len mode.

% shntool len *.shn
    length     expanded size   cdr  WAVE  probs   filename
    18:39.49     197506892     ---   --    -xx    gd72-08-27d2t01.shn
     8:48.56      93270956     ---   --    -xx    gd72-08-27d2t02.shn
     4:58.46      52675436     ---   --    -xx    gd72-08-27d2t03.shn
    12:18.62     130329068     ---   --    -xx    gd72-08-27d2t04.shn
     5:32.39      58656572     ---   --    -xx    gd72-08-27d2t05.shn
    50:18.27     532438924 B                      (totals for 5 files, 0.5612 overall compression ratio)
%

If all input files are compressed, then the totals line will show an overall
compression ratio for those files, as seen above.

Here are some files that show off many of the property/problem flags described
in the "Explanation of output columns" section below:

% shntool len < test.list
    length     expanded size   cdr  WAVE  probs   filename
     0:00             6030     cxx   --    ---    doh.wav
     0:00             6030     cxx   --    --j    doh-withjunk.wav
     4:08.31      43820156     ---   --    -xx    test-ok.shn
     4:08.31      43820156     ---   --    ---    test-ok.wav
     0:19           215420     cxx   he    ---    test-he.wav
     0:06           135876     cxx   -e    ---    test-e.wav
     0:06           135049     cxx   --    -t-    test-t.wav
     3:40.40      38901578     -b-   -e    -xx    test-be.shn
    10:01.65     106169336     ---   h-    -xx    test-h.shn
    22:32        233209631 B                      (totals for 9 files)
%

You can specify an alternate totals unit with the -u command-line switch.  For
example, running:

% shntool len -u mb *.shn

on the first set of files listed above will produce identical output, except for
the totals line which will be shown in terms of megabytes instead of bytes:

    50:18.27        507.77 MB                     (totals for 5 files, 0.5612 overall compression ratio)


Explanation of output columns
-----------------------------

The 'length' column shows the length of the WAVE data in that file, in m:ss
format.  If the WAVE data is CD-quality, then the length is shown in m:ss.ff
format, where ff is a number from 00 to 74 that best approximates the number of
frames (2352-byte blocks) remaining after m:ss.  If all files given are
CD-quality, then the total length is displayed in m:ss.ff format; otherwise, the
total length will be displayed in m:ss format.

Note on rounding:  If the WAVE data is CD-quality, then its length is rounded to
                   the nearest frame.  Otherwise, it is rounded to the nearest
                   second.

The 'expanded size' column shows the total size of the WAVE header, WAVE data
and any other RIFF chunks appended to the file.  Essentially this shows exactly
how large a file is (or will be when it is decompressed).

The following three columns - cdr, WAVE and probs - attempt to show properties
and/or problems associated with the corresponding file.  Each entry under a
particular column stands for a specific property/problem.  In all three columns,
whenever that entry is applicable and checks out okay, a '-' will appear in its
place; and whenever that entry is not applicable or cannot be determined, an 'x'
will appear in its place.  However, if a particular entry does not check out
okay, you will see a unique letter corresponding to what went wrong.  Read on
for more information about what these letters mean.

The 'cdr' column shows properties of CD-quality WAVE data.  There are three
entries under this column.  The first entry will contain a 'c' if the WAVE data
is not CD-quality.  The second entry will contain a 'b' if the data is
CD-quality, but not cut on a sector boundary.  The third entry will contain an
's' if the data is CD-quality, but too short to be burned (i.e. 705600 bytes - 4
seconds worth of CD-quality WAVE data).

The 'WAVE' column shows properties of the WAVE data for any file. These properties
are not problems; they are just indicators of WAVE data that is not canonical.
There are two entries under this column.  The first entry will contain an 'h' if
the WAVE header is not canonical (44 bytes). The second entry will contain an
'e' if the WAVE file contains extra RIFF chunks, other than the required 'fmt'
and 'data' chunks.  Files that exhibit one or both of these properties can be
made canonical by stripping the unnecessary data via shntool's built-in strip
mode.

The 'probs' column shows problems with the WAVE header and/or data for the given
file.  There are three entries under this column.  The first entry will contain
an 'i' if the header size plus the reported data size is greater than the
calculated total size taken from the header (i.e. chunk size + 8).  The second
entry will contain a 't' if the calculated total size is greater than the file's
actual size, and the file is not compressed (e.g. a .wav file).  The third entry
will contain a 'j' if the calculated total size is less than the file's actual
size, and the file is not compressed.  The last two entries are only verified
for WAVE data that is not compressed, since it would take far too long to verify
this for compressed WAVE data as well.

Summary of one-character abbreviations:

  all columns:

  '-'  this particular entry is OK
  'x'  this particular entry is not applicable or cannot be determined

  cdr column:

  'c'  data is not [C]D-quality
  'b'  CD-quality WAVE data is not cut on a sector [b]oundary
  's'  CD-quality WAVE data is too [s]hort to be burned

  WAVE column:

  'h'  WAVE [h]eader is not canonical
  'e'  WAVE file contains [e]xtra chunks

  probs column:

  'i'  WAVE header is [i]nconsistent about data size and/or file size
  't'  WAVE file seems to be [t]runcated
  'j'  WAVE file seems to have [j]unk appended to it


-------------
1b. info mode
-------------

Info mode shows a detailed, multi-line listing of the properties of a given
file.  Below is sample output from info mode when run on just one file.


% shntool info gd73-03-24d3t01.shn
-------------------------------------------------------------------------------
filename:                     gd73-03-24d3t01.shn
handled by:                   shn format module
length:                       13:41.45
WAVE format:                  0x0001 (Microsoft PCM)
channels:                     2
bits/sample:                  16
samples/sec:                  44100
average bytes/sec:            176400
rate (calculated):            176400
block align:                  4
header size:                  44 bytes
data size:                    144930240 bytes
chunk size:                   144930276 bytes
total size (chunk size + 8):  144930284 bytes
actual file size:             83698133 (compressed)
compression ratio:            0.5775
CD-quality properties:
  CD quality:                 yes
  cut on sector boundary:     yes
  long enough to be burned:   yes
WAVE properties:
  non-canonical header:       no
  extra RIFF chunks:          no
Possible problems:
  inconsistent header:        no
  file probably truncated:    n/a
  junk appended to file:      n/a


------------
1c. md5 mode
------------

md5 mode computes the MD5 hash of the WAVE data contained within input files.
This can be used to catalog unique sources of audio, and to determine whether
files stored in one format are identical in terms of audio data.  The string
"[shntool]" is added to the output to distinguish these MD5 sums from normal
MD5 sums.

Here is the output for one source of a particular show:

% shntool md5 *.shn
b3b7d3f6c6b0ffc88e6588f4f279d97e  [shntool]  ph1993-08-20d1t01.shn
dc989e4aa15b31b8389814d7ac945c87  [shntool]  ph1993-08-20d1t02.shn
e3e3276ce8c1d5aac3ba9c603d9a1810  [shntool]  ph1993-08-20d1t03.shn
1cc17eaef4c086222bbb5974e61de72f  [shntool]  ph1993-08-20d1t04.shn
6a1b42c3d592b3004212dc6ac36649ea  [shntool]  ph1993-08-20d1t05.shn
0c177bcb31e882efee9bd5930cf9c2ec  [shntool]  ph1993-08-20d1t06.shn
0bf26039c8bb42c15518f0c4988dd01e  [shntool]  ph1993-08-20d1t07.shn
b82f32b6c727e465ba7a925a2bf0f7f7  [shntool]  ph1993-08-20d1t08.shn
1164b3207df6916621808ff4ee2ac9b7  [shntool]  ph1993-08-20d1t09.shn
32dc984bd441a4703a5b65902583ec45  [shntool]  ph1993-08-20d2t01.shn
14f466e265499a56aacbfb7144057d37  [shntool]  ph1993-08-20d2t02.shn
8a35ff394515baa062610172f125e376  [shntool]  ph1993-08-20d2t03.shn
a23d9996e43df5107a802b3aba4a2830  [shntool]  ph1993-08-20d2t04.shn
8a35eb14fcbb0dacbad1915a07746400  [shntool]  ph1993-08-20d2t05.shn
1808c90d6728dd151eafd3d6135d1ee0  [shntool]  ph1993-08-20d2t06.shn
afe8dd6c67afa59d2f31fb04dc6a78c1  [shntool]  ph1993-08-20d2t07.shn
136f555973b5a92433522f0fccf05e7d  [shntool]  ph1993-08-20d3t01.shn
8cffae094165d8a5bffacd5198dd53a7  [shntool]  ph1993-08-20d3t02.shn
08c9532a2c07750cb7ccb5cbe678da6b  [shntool]  ph1993-08-20d3t03.shn
a8c76355bd329d563b79d4ac75485314  [shntool]  ph1993-08-20d3t04.shn
e2429980fd995cb19764b7768ff188e3  [shntool]  ph1993-08-20d3t05.shn
%

Here is an example showing how the MD5 sum of WAVE data remains constant
even though the compression formats differ:

% shntool md5 example.*
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.aiff
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.ape
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.flac
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.ofr
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.pac
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.shn
e09f22c64d717ed89c6009b52fcfddd2  [shntool]  example.wav
%

Here's one way to find the MD5 hash of all your audio files:

% find /audio/dir | shntool md5 2>/dev/null


==========================
2. Modes that create files
==========================

Currently, the modes that create output files are fix, join, split, strip and
conv.  These modes are highly configurable in terms of the output files they can
produce.  All of these modes support the following optional command-line
options (with the exception of conv mode, which does not support -p):

 -o format  (specifies output format, where format may be wav, shn, etc.)
 -d dir     (specifies an alternate output directory than the default)
 -p         (preview changes without actually making them)


------------
2a. fix mode
------------

The purpose of fix mode is to take a set of input files that contain CD-quality
WAVE data and rewrite them so that they are properly aligned on a sector
boundary.  It does this in one of three ways - it shifts track breaks backward
to the previous multiple of 2352 bytes whenever necessary, shifts track breaks
forward to the next multiple of 2352 bytes whenever necessary, or rounds track
breaks to the nearest multiple of 2352 bytes whenever necessary.  The default
action is to shift track breaks backward (though this may change to rounding
after it has been sufficiently tested, since this method minimizes the amount of
shifting performed).  The desired shift may be specified with the '-s'
command-line switch.

Given a set of files to correct, fix mode will start its fixing at the first
file that has a sector-boundary error.  This is intended to eliminate redundancy
and minimize the total amount of work done.  For example, consider the following
set of files:

% shntool len *.shn
    length     expanded size   cdr  WAVE  probs   filename
     2:59.54      31702652     ---   --    -xx    ph91-07-15d2t01.shn
    10:03.65     106522124     ---   --    -xx    ph91-07-15d2t02.shn
     5:08.23      54385340     ---   --    -xx    ph91-07-15d2t03.shn
     6:10.00      65268044     ---   --    -xx    ph91-07-15d2t04.shn
     4:46.43      50551300     -b-   --    -xx    ph91-07-15d2t05.shn
     8:29.39      89879372     ---   --    -xx    ph91-07-15d2t06.shn
     6:18.41      66775676     ---   --    -xx    ph91-07-15d2t07.shn
     1:35.53      16882436     -b-   --    -xx    ph91-07-15d2t08.shn
    45:32.18     481966944 B                      (totals for 8 files, 0.5567 overall compression ratio)
%

If you attempt to fix these files via 'shntool fix *.shn' or similar, then fix
mode will skip the first four files because they would not be changed (from a
WAVE data perspective).  If you want to force it to operate on all files
regardless of whether they would be modified, then use the '-noskip'
command-line switch.

By default, the last file will be padded with zero-bytes up to the next multiple
of 2352 bytes, if necessary.  This can be disabled via the '-nopad' option.

Output files will be named based on the corresponding input file, with "-fixed"
appended to the base part of the file name.  By default, output files are
created in the current directory, unless told otherwise via the '-d'
command-line switch.

Here is sample output from fix mode when run on the above files:

% shntool fix *.shn
shntool [fix]: warning: no output format specified - defaulting to wav
shntool [fix]: warning: no shift direction specified - assuming backward shift
shntool [fix]: warning: skipping first 4 files because they would not be changed
ph91-07-15d2t05.shn --> ph91-07-15d2t05-fixed.wav ... done.
ph91-07-15d2t06.shn --> ph91-07-15d2t06-fixed.wav ... done.
ph91-07-15d2t07.shn --> ph91-07-15d2t07-fixed.wav ... done.
ph91-07-15d2t08.shn --> ph91-07-15d2t08-fixed.wav ... done.
Padded 'ph91-07-15d2t08-fixed.wav' with 544 zero-bytes.
%

Here is sample output exhibiting several different options:

% shntool fix -o shn -s r -d /mnt/shn/tmp -nopad -noskip *.shn
ph91-07-15d2t01.shn --> /mnt/shn/tmp/ph91-07-15d2t01-fixed.shn ... done.
ph91-07-15d2t02.shn --> /mnt/shn/tmp/ph91-07-15d2t02-fixed.shn ... done.
ph91-07-15d2t03.shn --> /mnt/shn/tmp/ph91-07-15d2t03-fixed.shn ... done.
ph91-07-15d2t04.shn --> /mnt/shn/tmp/ph91-07-15d2t04-fixed.shn ... done.
ph91-07-15d2t05.shn --> /mnt/shn/tmp/ph91-07-15d2t05-fixed.shn ... done.
ph91-07-15d2t06.shn --> /mnt/shn/tmp/ph91-07-15d2t06-fixed.shn ... done.
ph91-07-15d2t07.shn --> /mnt/shn/tmp/ph91-07-15d2t07-fixed.shn ... done.
ph91-07-15d2t08.shn --> /mnt/shn/tmp/ph91-07-15d2t08-fixed.shn ... done.
File '/mnt/shn/tmp/ph91-07-15d2t08-fixed.shn' was not padded, though it needs 544 bytes of padding.
%

Here is a sample showing the preview capability:

% shntool fix -o wav -d ../disc1 -p -noskip *.wav
shntool [fix]: warning: no shift direction specified - assuming backward shift

Preview of changes:
-------------------

Track breaks will be shifted backward when necessary.

track1.wav --> ../disc1/track1-fixed.wav
  - beginning of track will remain unchanged
  - data size will remain unchanged

track10.wav --> ../disc1/track10-fixed.wav
  - beginning of track will remain unchanged
  - data size will remain unchanged

track2.wav --> ../disc1/track2-fixed.wav
  - beginning of track will remain unchanged
  - data size will remain unchanged

track3.wav --> ../disc1/track3-fixed.wav
  - beginning of track will remain unchanged
  - data size will remain unchanged

track4.wav --> ../disc1/track4-fixed.wav
  - beginning of track will remain unchanged
  - data size will remain unchanged

track5.wav --> ../disc1/track5-fixed.wav
  - beginning of track will remain unchanged
  - data size will decrease by 2072 bytes

track6.wav --> ../disc1/track6-fixed.wav
  - beginning of track will be moved backward by 2072 bytes
  - data size will remain unchanged

track7.wav --> ../disc1/track7-fixed.wav
  - beginning of track will be moved backward by 2072 bytes
  - data size will remain unchanged

track8.wav --> ../disc1/track8-fixed.wav
  - beginning of track will be moved backward by 2072 bytes
  - data size will increase by 264 bytes

track9.wav --> ../disc1/track9-fixed.wav
  - beginning of track will be moved backward by 1808 bytes
  - data size will increase by 1808 bytes

The last file '../disc1/track9-fixed.wav' would be padded with 544 zero-bytes.
%

The above example shows the usefulness of the '-order' switch, which allows you
to edit the order in which the files will be processed.  Using the online
editor, you can fix the list so that track 10 properly appears after track 9,
instead of after track 1.  This is usually simpler than specifying each track in
the correct order on the command line, although in the above case you can put
files in the correct order with:

% shntool fix -o wav -d ../disc1 -p -noskip track?.wav track??.wav

One final note on fix mode.  If you have a single track that is not properly
sector-aligned, and you want to shift the track break backward (i.e. truncate
the extra data, rather than pad it), then you are out of luck because fix mode
will not let you do this.  There is a workaround, though.  Simply use a second
dummy file (such as 1 second of silence), and run fix mode with backward shift
on both files.  When you are done, discard the second fixed file (the dummy
file) and the file you are left with will be your original file, truncated to
the previous sector boundary.  Here is an example:

% shntool fix -s b -nopad badfile.wav
shntool [fix]: warning: no output format specified - defaulting to wav
shntool [fix]: error: file 'badfile.wav' (the only file to process) won't be padded, so there is nothing to do
% shntool fix -s b -nopad badfile.wav dummy.wav
shntool [fix]: warning: no output format specified - defaulting to wav
badfile.wav --> badfile-fixed.wav ... done.
dummy.wav --> dummy-fixed.wav ... done.
File 'dummy-fixed.wav' was not padded, though it needs 1956 bytes of padding.
% shntool len badfile.wav badfile-fixed.wav
    length     expanded size   cdr  WAVE  probs   filename
     2:46.21      29332232     -b-   --    ---    badfile.wav
     2:46.21      29331836     ---   --    ---    badfile-fixed.wav
     5:32.42      58664068 B                      (totals for 2 files)
%

Notice that badfile-fixed.wav is now the backward-shifted (truncated) version of
badfile.wav, which is what we wanted.  Now remove 'dummy-fixed.wav', and you're
done.


-------------
2b. join mode
-------------

The purpose of join mode is to concatenate WAVE data from multiple files into
one output file.  This can be useful if you want to completely retrack a show,
not just fix sector boundary problems.  Note that all input files must have the
same WAVE format, number of channels, samples per second, bits per sample and
rate - otherwise shntool can't join them.  If all input files are CD-quality,
then by default the output file will be padded with zero-bytes up to the next
multiple of 2352 bytes, if necessary.  This can be disabled via the '-nopad'
option.  Unless you use the '-stdout' option, the output file will be named
'joined.ext', where 'ext' is the extension of the output file format.  It will
be created in the current directory unless told otherwise via the '-d'
command-line switch.  The default output format is 'wav' for unmodified builds
of shntool.  Below is a sample of what you will see if you join mode with no
options:

% shntool join *.shn
shntool [join]: warning: no output format specified - defaulting to wav
Adding contents of gd73-03-24d3t01.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t02.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t03.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t04.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t05.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t06.shn to joined.wav ... done.
Adding contents of gd73-03-24d3t07.shn to joined.wav ... done.
No padding needed for 'joined.wav'.
%

Here is an example using -stdout to pipe to another process:

% shntool join -stdout disc?/*.shn | lame - > stretch93-10-15.mp3 2>/dev/null
shntool [join]: warning: no output format specified - defaulting to wav
Adding contents of disc1/stretch93-10-15d1t01.shn to stdout ... done.
Adding contents of disc1/stretch93-10-15d1t02.shn to stdout ... done.
Adding contents of disc1/stretch93-10-15d1t03.shn to stdout ... done.
(many lines snipped for brevity)
Adding contents of disc3/stretch93-10-15d3t11.shn to stdout ... done.
Adding contents of disc3/stretch93-10-15d3t12.shn to stdout ... done.
Adding contents of disc3/stretch93-10-15d3t13.shn to stdout ... done.
No padding needed for 'stdout'.
%

Here is an example that exhibits several options:

% shntool join -d /mnt/shn/tmp -o shn -nopad *.wav
Adding contents of test01.wav to /mnt/shn/tmp/joined.shn ... done.
Adding contents of test02.wav to /mnt/shn/tmp/joined.shn ... done.
Adding contents of test03.wav to /mnt/shn/tmp/joined.shn ... done.
Adding contents of test04.wav to /mnt/shn/tmp/joined.shn ... done.
Adding contents of test05.wav to /mnt/shn/tmp/joined.shn ... done.
File 'joined.shn' was not padded, though it needs 1844 bytes of padding.
%

Here are a couple of samples showing the preview capability:

% shntool join -p doh.wav doh.wav

Preview of changes:
-------------------

WAVE data from the following files:

  doh.wav
  doh.wav

will be joined into file 'joined.wav', in the order shown above.

Padding would not apply to these files because they are not CD-quality.
%

% shntool join -p -d /mnt/shn/tmp -o wav *.wav

Preview of changes:
-------------------

WAVE data from the following files:

  test1.wav
  test10.wav
  test11.wav
  test12.wav
  test2.wav
  test3.wav
  test4.wav
  test5.wav
  test6.wav
  test7.wav
  test8.wav
  test9.wav

will be joined into file '/mnt/shn/tmp/joined.wav', in the order shown above.

This file wouldn't be padded, but would need 2176 bytes of padding.
%

The above example shows the usefulness of the '-order' switch, which allows you
to edit the order in which the files will be processed.  Using the online
editor, you can fix the list so that tracks 10 through 12 properly appear after
track 9.  This is usually simpler than specifying each track in the correct
order on the command line, although in the above case you can put files in the
correct order with:

% shntool join -d /mnt/shn/tmp -o wav test?.wav test??.wav


--------------
2c. split mode
--------------

The purpose of split mode is to create multiple files from a single input file. 
Track breaks are defined by split points, which can be in any of the following
formats:

bytes      (explicit byte offset from beginning of WAVE data)
m:ss       (standard minutes:seconds format)
m:ss.ff    (minutes:seconds:frames format, where a frame is 1/75 of a second)
m:ss.nnn   (minutes:seconds:milliseconds format)

NOTE: m:ss.ff can only be used with CD-quality input files.

All of the above formats (except for bytes) are converted to byte offsets.  If
the input file is CD-quality, then the byte offsets are rounded to the nearest
sector boundary.  If you want to force non-sector aligned track boundaries, use
the explicit byte offset format.

Split points can be read from standard input, or from a file via the '-f'
command-line switch.  They must appear in increasing order, and must not go
beyond the size of the WAVE data in the input file.  If the last split point's
calculated byte offset falls at the very end of the input file's WAVE data, then
it is ignored.

In the following examples, the contents of the split points files are shown for
reference.

Here is a sample invocation of split mode:

% cat offsets3
0:13.25
0:26.50
0:40.00
0:53.25
1:06.50
1:20.00
1:33.25
1:46.50
% shntool split test.wav < offsets3
shntool [split]: warning: no output format specified - defaulting to wav

Input file 'test.wav' is being split into 9 pieces.

Writing split-track01.wav (0:13.25) ... done.
Writing split-track02.wav (0:13.25) ... done.
Writing split-track03.wav (0:13.25) ... done.
Writing split-track04.wav (0:13.25) ... done.
Writing split-track05.wav (0:13.25) ... done.
Writing split-track06.wav (0:13.25) ... done.
Writing split-track07.wav (0:13.25) ... done.
Writing split-track08.wav (0:13.25) ... done.
Writing split-track09.wav (0:04.74) ... done.
%

You can change aspects of the output file names via the '-n' and '-c'
command-line switches:

% cat offsets4
0:13.333
0:26.667
0:40.000
0:53.333
1:06.667
1:20.000
1:33.333
1:46.667
% shntool split -o shn -f offsets4 -n mytest -c 7 test.wav
shntool [split]: warning: rounding 0:13.333 (offset: 2351941) to nearest sector boundary (offset: 2352000)
shntool [split]: warning: rounding 0:26.667 (offset: 4704059) to nearest sector boundary (offset: 4704000)
shntool [split]: warning: rounding 0:53.333 (offset: 9407941) to nearest sector boundary (offset: 9408000)
shntool [split]: warning: rounding 1:06.667 (offset: 11760059) to nearest sector boundary (offset: 11760000)
shntool [split]: warning: rounding 1:33.333 (offset: 16463941) to nearest sector boundary (offset: 16464000)
shntool [split]: warning: rounding 1:46.667 (offset: 18816059) to nearest sector boundary (offset: 18816000)

Input file 'test.wav' is being split into 9 pieces.

Writing mytest07.shn (0:13.25) ... done.
Writing mytest08.shn (0:13.25) ... done.
Writing mytest09.shn (0:13.25) ... done.
Writing mytest10.shn (0:13.25) ... done.
Writing mytest11.shn (0:13.25) ... done.
Writing mytest12.shn (0:13.25) ... done.
Writing mytest13.shn (0:13.25) ... done.
Writing mytest14.shn (0:13.25) ... done.
Writing mytest15.shn (0:04.74) ... done.
%

Finally, you can preview what changes would be made before actually making them
with the '-p' switch:

% cat offsets7
0:13
4704001
0:40.00
0:53.333
11760000
% shntool split -d /mnt/shn/tmp -p -n output_ -c 0 test.wav < offsets7
shntool [split]: warning: no output format specified - defaulting to wav
shntool [split]: warning: file 2 will not be cut on a sector boundary
shntool [split]: warning: file 3 will not be cut on a sector boundary
shntool [split]: warning: rounding 0:53.333 (offset: 9407941) to nearest sector boundary (offset: 9408000)

Preview of changes:
-------------------

File 'test.wav' will be split into 6 pieces:

  + /mnt/shn/tmp/output_00.wav (0:13.00)
    - this file will contain 2293200 bytes of WAVE data (plus 44-byte header)

  + /mnt/shn/tmp/output_01.wav (0:13.50)
    - this file will contain 2410801 bytes of WAVE data (plus 44-byte header)
    - this file will not be cut on a sector boundary

  + /mnt/shn/tmp/output_02.wav (0:13.25)
    - this file will contain 2351999 bytes of WAVE data (plus 44-byte header)
    - this file will not be cut on a sector boundary

  + /mnt/shn/tmp/output_03.wav (0:13.25)
    - this file will contain 2352000 bytes of WAVE data (plus 44-byte header)

  + /mnt/shn/tmp/output_04.wav (0:13.25)
    - this file will contain 2352000 bytes of WAVE data (plus 44-byte header)

  + /mnt/shn/tmp/output_05.wav (0:44.74)
    - this file will contain 7935648 bytes of WAVE data (plus 44-byte header)
%


--------------
2d. strip mode
--------------

The purpose of strip mode is to remove extraneous data from files.  It has the
ability to shrink WAVE headers down to the canonical 44-byte header, and also to
remove extra RIFF chunks from the end of WAVE streams, which usually contain
miscellaneous information about the program used to create or edit the WAVE data
in that file.  Since neither having a non-canonical header nor containing extra
RIFF chunks are harmful in and of themselves, it is usually not necessary to use
this mode.  The only time you may want to use it is when you encounter a program
that cannot load a particular WAVE file because it expects it to have a
canonical header and/or expects that nothing follows the 'data' chunk in the
WAVE stream.

By default, headers are canonicalized, and extra RIFF chunks are stripped.  You
can disable one or the other of these actions via the '-nh' (no header) and
'-nc' (no chunks) switches.  Output files will be named based on the
corresponding input file, with "-stripped" appended to the base part of the file
name.  By default, output files are created in the same directory as the
corresponding input file, unless told otherwise via the '-d' command-line
switch.  File names are read from the command line, or from standard input if
none are specified on the command line.  Here is a sample run of strip mode:

% shntool strip a.wav tms.shn
shntool [strip]: warning: no output format specified - defaulting to wav
a.wav --> a-stripped.wav ... done.
tms.shn --> tms-stripped.wav ... done.
%

You can preview what would be done with the '-p' switch (note the use of the
'-d' and '-o' switches as well):

% shntool strip -o shn -p -d /mnt/shn/tmp a.wav p2.wav

Preview of changes:
-------------------

a.wav --> /mnt/shn/tmp/a-stripped.shn
  - will rewrite 46-byte WAVE header to the canonical 44-byte header
  - will strip 1 byte worth of extra RIFF chunk(s) from the end of this file

p2.wav --> /mnt/shn/tmp/p2-stripped.shn
  - will strip 827 bytes worth of extra RIFF chunk(s) from the end of this file

%

Here is what happens when you run strip mode on the above files, but specify not
to strip extra RIFF chunks:

% shntool strip -o shn -d /mnt/shn/tmp -nc a.wav p2.wav
a.wav --> /mnt/shn/tmp/a-stripped.shn ... done.
shntool [strip]: error: skipping file 'p2.wav' because it already has a canonical header
%


-------------
2e. conv mode
-------------

The purpose of conv mode is to convert a set of input files to a specified
output format.  File names are read from the command line; if none are given,
file names are read from standard input.  If the input file format matches the
desired output file format, that file is skipped.

Output files are named based on the input file name.  Specifically, if the input
file name ends with the default file extension for that file's format, then the
default extension for the desired output format will replace it; otherwise, the
default extension for the desired output format will be appended to it.  For
example, for an output format of shn and a wav input file named 'file.wav', the
converted file will be named 'file.shn', since '.wav' is shntool's default
extension for the wav format.  On the other hand, given the same situation
above, but with an input file named 'file.wave', the converted file will be
named 'file.wave.shn', since '.wave' does not match '.wav'.

By default, output files are created in the same directory as the input file.
This can be altered with the -d switch.

Here is one way to convert a set of SHN files to FLAC:

% shntool conv -o flac *.shn
converting 'gd73-03-24d3t01.shn' to 'gd73-03-24d3t01.flac' ... done.
converting 'gd73-03-24d3t02.shn' to 'gd73-03-24d3t02.flac' ... done.
converting 'gd73-03-24d3t03.shn' to 'gd73-03-24d3t03.flac' ... done.
converting 'gd73-03-24d3t04.shn' to 'gd73-03-24d3t04.flac' ... done.
converting 'gd73-03-24d3t05.shn' to 'gd73-03-24d3t05.flac' ... done.
converting 'gd73-03-24d3t06.shn' to 'gd73-03-24d3t06.flac' ... done.
converting 'gd73-03-24d3t07.shn' to 'gd73-03-24d3t07.flac' ... done.
%

Here is an example that converts files in different directories, placing the
output files in a specified directory:

% find gd72-08-27 -name \*.shn | shntool conv -o aiff -d tmp
converting 'gd72-08-27/disc1/gd72-08-27d1t01.shn' to 'tmp/gd72-08-27d1t01.aiff' ... done.
converting 'gd72-08-27/disc1/gd72-08-27d1t02.shn' to 'tmp/gd72-08-27d1t02.aiff' ... done.
converting 'gd72-08-27/disc1/gd72-08-27d1t03.shn' to 'tmp/gd72-08-27d1t03.aiff' ... done.
(many lines snipped for brevity)
converting 'gd72-08-27/disc3/gd72-08-27d3t05.shn' to 'tmp/gd72-08-27d3t05.aiff' ... done.
converting 'gd72-08-27/disc3/gd72-08-27d3t06.shn' to 'tmp/gd72-08-27d3t06.aiff' ... done.
converting 'gd72-08-27/disc3/gd72-08-27d3t07.shn' to 'tmp/gd72-08-27d3t07.aiff' ... done.
%

Here is an example with many different input file formats, as well as
non-standard file extensions:

% shntool conv example*
shntool [conv]: warning: no output format specified - defaulting to wav
converting 'example1.aiff' to 'example1.wav' ... done.
converting 'example2.ape' to 'example2.wav' ... done.
converting 'example3.flac' to 'example3.wav' ... done.
converting 'example4.shn' to 'example4.wav' ... done.
converting 'example5.ofr' to 'example5.wav' ... done.
converting 'example6.pac' to 'example6.wav' ... done.
converting 'example7.unknown' to 'example7.unknown.wav' ... done.
shntool [conv]: error: input format for 'example8.wav' matches output format, skipping.
shntool [conv]: error: input format for 'example9.woohoo' matches output format, skipping.
shntool [conv]: error: input format for 'example10' matches output format, skipping.
%

An unintended use for conv mode is to verify that files are not truncated,
by converting files to the 'null' output format.  This output format simply
discards any data it receives, so it doesn't create any output files.
Examples are below.

Here is sample output for an intact, non-truncated file:

% shntool conv -o null test.shn
converting 'test.shn' to 'test.null (actually /dev/null)' ... done.
%

Here is sample output for a truncated file:

% shntool conv -o null truncated.shn
converting 'truncated.shn' to 'truncated.null (actually /dev/null)' ... 
shntool [conv]: warning: tried to read 76496 bytes, but only read 75776 - possible truncated/corrupt file
shntool [conv]: error: error while transferring 23931600-byte data chunk
%


======================
3. Miscellaneous modes
======================

The following modes don't quite fit in the categories listed above.

------------
3a. cat mode
------------

The purpose of cat mode is to write (catenate) the WAVE header, WAVE data,
and/or extra RIFF chunks from one or more files to standard output.  This can be
useful for things like on-the-fly CD burning or streaming audio.  I also use it
to verify the correctness of split, fixed, and joined files, by comparing
md5sums of the raw WAVE data for the input and output files.  Typing:

% shntool cat filename

or

% echo "filename" | shntool cat

will write the WAVE header, WAVE data, and any extra RIFF chunks from the given
file to standard output.  If you want to suppress the WAVE header and extra RIFF
chunks (which, if not suppressed, can cause 'clicks' at the beginning and/or end
of tracks when piping output to a CD-burning program that expects raw WAVE
data), then give the '-nh' (no header) and '-nr' (no extra RIFF chunks)
switches:

% shntool cat -nh -nr filename

If you only need to output the WAVE header, then use the '-nd' (no data) and
'-nr' switches:

% shntool cat -nd -nr filename

The only use I can think of for this at the moment is for bug reporting.
Sometimes I only need to see WAVE headers to debug a problem, and this provides
a way for you to get them to me.  I hope you never have to use this option for
that reason, though.  :^)


------------
3b. cmp mode
------------

The purpose of cmp mode is to compare the WAVE data contained within two files.
This is useful if you want to verify the results CD-audio extraction against the
original files.  This can also be used to compare the WAVE data within two files
of different formats (e.g. file1.wav and file2.shn), for which other methods of
verification such as md5sum will not do.  Since this mode ignores WAVE headers
and extra RIFF chunks when making the comparison, it can also be used to compare
files that have been stripped (see strip mode above) to their unstripped
counterparts, which is another situation where md5sum would not be sufficient.

Before running the comparison, the WAVE headers are examined for differences.
If any value in the headers differ other than the reported data size or the
block align, then an error is reported and the files are not compared.
Otherwise, if the size of the WAVE data differs in the two files to be compared,
then a comparison is run only up to the size of the smaller of the two; and if
the block align values differ, then a warning is printed (since some CD-quality
WAVE files have headers that report a block align of 4 instead of 2), but the
comparison continues (since it seems that the block align is often ignored by
programs).

When run normally, cmp mode will either say the files are identical, or exit at
the first differing byte.  If you want to see all differing bytes (and their
values), use the -l option.  If any bytes differ, you will see a list of
offsets, similar to 'cmp -l' under UNIX.  In particular, offsets are 1-based,
meaning the first byte is offset 1, not 0.  The byte values of the differing
bytes in each file are also shown for reference.

Sometimes you might want to compare data in two files, one of which might
contain extra bytes at the beginning (such as a file ripped from a CD burned TAO
which might have an initial 2-second gap of silence, depending on the program
used to rip it).  In this case, you can use the -s option to have shntool
determine whether one of the files contains extra bytes at the beginning of the
WAVE data.  This option can also help identify a CD burner/CD reader combined
read/write offset.  Currently, only the first 529200 bytes (3 seconds of
CD-quality WAVE data) are searched for identicalness, but this should be more
than enough for most purposes.  If for some reason you believe that the files
are byte-shifted, but shntool does not think so, you can use the -f switch to
give shntool a "fuzz factor" that it will use.  This fuzz factor is simply a
positive integer that represents the maximum number of allowable byte mismatches
within the first 529200 bytes.  This allows you to check for differing bytes
between to files that (a) are byte-shifted and (b) contain at least one error
within the first 529200 bytes (an error that could have been cause by an
unreadable section of the CD, an unreliable CD reader, a bad hard drive/hard
drive cable, a network error, buggy hardware drivers, etc.).  The higher the
fuzz factor, the longer the -s option takes, so set it low at first (e.g. 8),
and increase it in small steps if needed.  Note that the -f option can only be
used with the -s option, since that's the only time the fuzz factor is used.

Here's an example comparison:

% shntool cmp test.wav test2.shn
comparing WAVE data in 'test.wav' and 'test2.shn' ... 

contents of these files are identical.
%

Here's what you will see if the WAVE data sizes differ, but are identical up to
the WAVE data size of the smaller file:

% shntool cmp cmp1a.wav cmp1b.wav
shntool [cmp]: warning: size of data to be compared differs between these files -
                        WAVE data will only be compared up to the smaller size
comparing WAVE data in 'cmp1a.wav' and 'cmp1b.wav' ... 

contents of these files are identical (up to the first 29332188 bytes of WAVE data).
%

Here's an example of what you might see if the WAVE data itself differs:

% shntool cmp test.wav test3.wav
comparing WAVE data in 'test.wav' and 'test3.wav' ... 

WAVE data differs at byte offset 9847801.
%

Curious what the differences were in the above case?  Let's see:

% shntool cmp -l test.wav test3.wav
comparing WAVE data in 'test.wav' and 'test3.wav' ... 

    offset   1   2
   ----------------
   9847801  13 157
  10619542 216  47

contents of these files differed as indicated above.
%

Now let's check a ripped file against its pre-burned couterpart:

% shntool cmp preburned.shn ripped.wav
shntool [cmp]: warning: size of data to be compared differs between these files -
                        WAVE data will only be compared up to the smaller size
comparing WAVE data in 'preburned.shn' and 'ripped.wav' ... 

WAVE data differs at byte offset 1.
%

Oops, we should have used the -s option:

% shntool cmp -s preburned.shn ripped.wav
checking for byte-shift between input files...

file 'ripped.wav' seems to have:

  350448 extra bytes (87612 extra samples, or 149 extra sectors)

these extra bytes will be discarded before comparing the data.

preparing to do full comparison...

comparing aligned WAVE data in 'preburned.shn' and 'ripped.wav' ... 

aligned contents of these files are identical.
%

Let's check two files that we think are identical, but one of which was ripped
from a sun-bleached, flaking, scratched CD:

% shntool cmp -s preburned2.shn ripped2.wav
checking for byte-shift between input files...

'preburned2.shn' and 'ripped2.wav' do not share identical data within the first 529200 bytes.
%

Hmm, I still think they are identical... let's use a fuzz factor to check:

% shntool cmp -s -f 8 preburned2.shn ripped2.wav
checking for byte-shift between input files...

with fuzz factor 8, file 'ripped2.wav' seems to have:

  350448 extra bytes (87612 extra samples, or 149 extra sectors)

these extra bytes will be discarded before comparing the data.

preparing to do full comparison...

shntool [cmp]: warning: size of data to be compared differs between these files -
                        WAVE data will only be compared up to the smaller size
comparing aligned WAVE data in 'preburned2.shn' and 'ripped2.wav' ... 

WAVE data differs at byte offset 137.
%

Hmm, I wonder where else they differ:

% shntool cmp -s -f 8 -l preburned2.shn ripped2.wav
checking for byte-shift between input files...

with fuzz factor 8, file 'ripped2.wav' seems to have:

  350448 extra bytes (87612 extra samples, or 149 extra sectors)

these extra bytes will be discarded before comparing the data.

preparing to do full comparison...

shntool [cmp]: warning: size of data to be compared differs between these files -
                        WAVE data will only be compared up to the smaller size
comparing aligned WAVE data in 'preburned2.shn' and 'ripped2.wav' ... 

    offset   1   2
   ----------------
       137 227 228
      1653 216 215
     56820  13 157

aligned contents of these files differed as indicated above.
%


========================
4. Custom format modules
========================

There is only one custom format module, 'cust'.  It is described below.

---------------
4a. cust format
---------------

The cust format provides the user with a means of specifying the precise
program and arguments shntool should use to encode output files.  This is
useful for overriding shntool's defaults for existing output formats, and
for enabling shntool to create files in a format that it does not yet
officially support.  The cust format has a simple format:

  { program argument_1 argument_2 ... argument_N }

This will create files with an extension of .custom by default.  If you wish
to provide your own extension (e.g. 'abc'), use this format:

  ext=abc { program argument_1 argument_2 ... argument_N }

NOTE:
-----
  At least one of the arguments must contain the string '%f', which is the
  placeholder for the output filename.  The cust format module will stick
  the output filename here, with the appropriate extension.

NOTE TO WINDOWS USERS:
----------------------
  Due to the way the Windows command prompt operates, you will need to put
  quotes around the curly braces, i.e.:  '{' program argument_1 ... '}'
  Also, if you use cust mode inside a batch file, you must use '%%f' instead
  of '%f'.


Here are two example uses for the cust output format.  The first shows how
you can use it to override an existing format module's default options, and
the second shows how you can use it to encode to a totally new format.

1.  Suppose you want to fix a set of files, and in the process create .shn's
    that are NOT seekable.  Here's one way to do it.  Note that although
    the output shows an extension of .custom, the files will really have the
    specified extension of .shn:

% shntool fix -noskip -o cust ext=shn { shorten -v2 - %f } *.shn
shntool [fix]: warning: no shift direction specified - assuming backward shift
gd80-10-11d1t01.shn --> gd80-10-11d1t01-fixed.custom ... done.
gd80-10-11d1t02.shn --> gd80-10-11d1t02-fixed.custom ... done.
gd80-10-11d1t03.shn --> gd80-10-11d1t03-fixed.custom ... done.
gd80-10-11d1t04.shn --> gd80-10-11d1t04-fixed.custom ... done.
gd80-10-11d1t05.shn --> gd80-10-11d1t05-fixed.custom ... done.
gd80-10-11d1t06.shn --> gd80-10-11d1t06-fixed.custom ... done.
gd80-10-11d1t07.shn --> gd80-10-11d1t07-fixed.custom ... done.
gd80-10-11d1t08.shn --> gd80-10-11d1t08-fixed.custom ... done.
gd80-10-11d1t09.shn --> gd80-10-11d1t09-fixed.custom ... done.
gd80-10-11d1t10.shn --> gd80-10-11d1t10-fixed.custom ... done.
No padding needed for 'gd80-10-11d1t10-fixed.custom'.
% shntool info *fixed.shn | grep seekable
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
  seekable:                   no
%

An alternate way of specifying the .shn extension is as follows:

% shntool fix -noskip -o cust ext= { shorten -v2 - %fshn } *.shn


2.  Suppose you want to convert a set of files to a new format that shntool
    does not currently support.  Let's make one up named 'crunch'.  Assuming
    this made-up format has a command-line program that will encode WAVE data
    read on standard input, all you have to do is figure out the proper
    arguments for doing so and plug it into the cust format module:

% shntool conv -o cust ext=crunch { wavcrunch -level 9 -input - -output new-%f } *.wav
converting 'test1.wav' to 'test1.custom' ... done.
converting 'test2.wav' to 'test2.custom' ... done.
converting 'test3.wav' to 'test3.custom' ... done.
%

Again, the files created above would have the specified extension of .crunch, not
the .custom extension shown.  Also, each file would be prefixed with the string
"new-", since that's what was specified to the encoder.  Thus, the three files
created in the above example would be named "new-test1.crunch", "new-test2.crunch"
and "new-test3.crunch".


==================
Document revision:
==================

$Id: TUTORIAL,v 1.38 2003/03/20 05:14:54 jason Exp $
