Initial commit

added libraries:
opus
flac
libsndfile

updated:
libvorbis
libogg
openal

- Everything works as expected for now. Bare in mind libsndfile needed the check for whether or not it could find the xiph libraries removed in order for this to work.
This commit is contained in:
marauder2k7 2024-03-21 17:33:47 +00:00
parent 05a083ca6f
commit a745fc3757
1954 changed files with 431332 additions and 21037 deletions

View file

@ -0,0 +1,503 @@
/*
** Copyright (C) 1999-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2008 George Blood Audio
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdint.h>
#include <math.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN 4096
#define MIN(x, y) ((x) < (y) ? (x) : (y))
int
sfe_copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels, int normalize)
{ static double data [BUFFER_LEN], max ;
sf_count_t frames, readcount, k ;
frames = BUFFER_LEN / channels ;
readcount = frames ;
sf_command (infile, SFC_CALC_SIGNAL_MAX, &max, sizeof (max)) ;
if (!isnormal (max)) /* neither zero, subnormal, infinite, nor NaN */
return 1 ;
if (!normalize && max < 1.0)
{ while (readcount > 0)
{ readcount = sf_readf_double (infile, data, frames) ;
sf_writef_double (outfile, data, readcount) ;
} ;
}
else
{ sf_command (infile, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
while (readcount > 0)
{ readcount = sf_readf_double (infile, data, frames) ;
for (k = 0 ; k < readcount * channels ; k++)
{ data [k] /= max ;
if (!isfinite (data [k])) /* infinite or NaN */
return 1 ;
}
sf_writef_double (outfile, data, readcount) ;
} ;
} ;
return 0 ;
} /* sfe_copy_data_fp */
void
sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels)
{ static int data [BUFFER_LEN] ;
int frames, readcount ;
frames = BUFFER_LEN / channels ;
readcount = frames ;
while (readcount > 0)
{ readcount = (int) sf_readf_int (infile, data, frames) ;
sf_writef_int (outfile, data, readcount) ;
} ;
return ;
} /* sfe_copy_data_int */
/*==============================================================================
*/
static int
merge_broadcast_info (SNDFILE * infile, SNDFILE * outfile, int format, const METADATA_INFO * info)
{ SF_BROADCAST_INFO_2K binfo ;
int infileminor ;
memset (&binfo, 0, sizeof (binfo)) ;
if ((SF_FORMAT_TYPEMASK & format) != SF_FORMAT_WAV)
{ printf ("Error : This is not a WAV file and hence broadcast info cannot be added to it.\n\n") ;
return 1 ;
} ;
infileminor = SF_FORMAT_SUBMASK & format ;
switch (infileminor)
{ case SF_FORMAT_PCM_16 :
case SF_FORMAT_PCM_24 :
case SF_FORMAT_PCM_32 :
case SF_FORMAT_MPEG_LAYER_III :
break ;
default :
printf (
"Warning : The EBU Technical Recommendation R68-2000 states that the only\n"
" allowed encodings are Linear PCM and MPEG3. This file is not in\n"
" the right format.\n\n"
) ;
break ;
} ;
if (sf_command (infile, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0)
{ if (infile == outfile)
{ printf (
"Error : Attempting in-place broadcast info update, but file does not\n"
" have a 'bext' chunk to modify. The solution is to specify both\n"
" input and output files on the command line.\n\n"
) ;
return 1 ;
} ;
} ;
#define REPLACE_IF_NEW(x) \
if (info->x != NULL) \
{ memset (binfo.x, 0, sizeof (binfo.x)) ; \
memcpy (binfo.x, info->x, MIN (strlen (info->x), sizeof (binfo.x))) ; \
} ;
REPLACE_IF_NEW (description) ;
REPLACE_IF_NEW (originator) ;
REPLACE_IF_NEW (originator_reference) ;
REPLACE_IF_NEW (origination_date) ;
REPLACE_IF_NEW (origination_time) ;
REPLACE_IF_NEW (umid) ;
/* Special case loudness values */
#define REPLACE_IF_NEW_INT(x) \
if (info->x != NULL) \
{ binfo.x = round (atof (info->x) * 100.0) ; \
} ;
REPLACE_IF_NEW_INT (loudness_value) ;
REPLACE_IF_NEW_INT (loudness_range) ;
REPLACE_IF_NEW_INT (max_true_peak_level) ;
REPLACE_IF_NEW_INT (max_momentary_loudness) ;
REPLACE_IF_NEW_INT (max_shortterm_loudness) ;
/* Special case for Time Ref. */
if (info->time_ref != NULL)
{ uint64_t ts = atoll (info->time_ref) ;
binfo.time_reference_high = (ts >> 32) ;
binfo.time_reference_low = (ts & 0xffffffff) ;
} ;
/* Special case for coding_history because we may want to append. */
if (info->coding_history != NULL)
{ if (info->coding_hist_append)
{ int slen = (int) strlen (binfo.coding_history) ;
while (slen > 1 && isspace (binfo.coding_history [slen - 1]))
slen -- ;
memcpy (binfo.coding_history + slen, info->coding_history, sizeof (binfo.coding_history) - slen) ;
}
else
{ size_t slen = MIN (strlen (info->coding_history), sizeof (binfo.coding_history)) ;
memset (binfo.coding_history, 0, sizeof (binfo.coding_history)) ;
memcpy (binfo.coding_history, info->coding_history, slen) ;
binfo.coding_history_size = (uint32_t) slen ;
} ;
} ;
if (sf_command (outfile, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0)
{ printf ("Error : Setting of broadcast info chunks failed.\n\n") ;
return 1 ;
} ;
return 0 ;
} /* merge_broadcast_info*/
static void
update_strings (SNDFILE * outfile, const METADATA_INFO * info)
{
if (info->title != NULL)
sf_set_string (outfile, SF_STR_TITLE, info->title) ;
if (info->copyright != NULL)
sf_set_string (outfile, SF_STR_COPYRIGHT, info->copyright) ;
if (info->artist != NULL)
sf_set_string (outfile, SF_STR_ARTIST, info->artist) ;
if (info->comment != NULL)
sf_set_string (outfile, SF_STR_COMMENT, info->comment) ;
if (info->date != NULL)
sf_set_string (outfile, SF_STR_DATE, info->date) ;
if (info->album != NULL)
sf_set_string (outfile, SF_STR_ALBUM, info->album) ;
if (info->license != NULL)
sf_set_string (outfile, SF_STR_LICENSE, info->license) ;
} /* update_strings */
void
sfe_apply_metadata_changes (const char * filenames [2], const METADATA_INFO * info)
{ SNDFILE *infile = NULL, *outfile = NULL ;
SF_INFO sfinfo ;
METADATA_INFO tmpinfo ;
int error_code = 0 ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
memset (&tmpinfo, 0, sizeof (tmpinfo)) ;
if (filenames [1] == NULL)
infile = outfile = sf_open (filenames [0], SFM_RDWR, &sfinfo) ;
else
{ infile = sf_open (filenames [0], SFM_READ, &sfinfo) ;
/* Output must be WAV. */
sfinfo.format = SF_FORMAT_WAV | (SF_FORMAT_SUBMASK & sfinfo.format) ;
outfile = sf_open (filenames [1], SFM_WRITE, &sfinfo) ;
} ;
if (infile == NULL)
{ printf ("Error : Not able to open input file '%s' : %s\n", filenames [0], sf_strerror (infile)) ;
error_code = 1 ;
goto cleanup_exit ;
} ;
if (outfile == NULL)
{ printf ("Error : Not able to open output file '%s' : %s\n", filenames [1], sf_strerror (outfile)) ;
error_code = 1 ;
goto cleanup_exit ;
} ;
if (info->has_bext_fields && merge_broadcast_info (infile, outfile, sfinfo.format, info))
{ error_code = 1 ;
goto cleanup_exit ;
} ;
if (infile != outfile)
{ int infileminor = SF_FORMAT_SUBMASK & sfinfo.format ;
/* If the input file is not the same as the output file, copy the data. */
if ((infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT))
{ if (sfe_copy_data_fp (outfile, infile, sfinfo.channels, SF_FALSE) != 0)
{ printf ("Error : Not able to decode input file '%s'\n", filenames [0]) ;
error_code = 1 ;
goto cleanup_exit ;
} ;
}
else
sfe_copy_data_int (outfile, infile, sfinfo.channels) ;
} ;
update_strings (outfile, info) ;
cleanup_exit :
if (outfile != NULL && outfile != infile)
sf_close (outfile) ;
if (infile != NULL)
sf_close (infile) ;
if (error_code)
exit (error_code) ;
return ;
} /* sfe_apply_metadata_changes */
/*==============================================================================
*/
typedef struct
{ const char *ext ;
int len ;
int format ;
} OUTPUT_FORMAT_MAP ;
/* Map a file name extension to a container format. */
static OUTPUT_FORMAT_MAP format_map [] =
{
{ "wav", 0, SF_FORMAT_WAV },
{ "aif", 3, SF_FORMAT_AIFF },
{ "au", 0, SF_FORMAT_AU },
{ "snd", 0, SF_FORMAT_AU },
{ "raw", 0, SF_FORMAT_RAW },
{ "gsm", 0, SF_FORMAT_RAW | SF_FORMAT_GSM610 },
{ "vox", 0, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM },
{ "paf", 0, SF_FORMAT_PAF | SF_ENDIAN_BIG },
{ "fap", 0, SF_FORMAT_PAF | SF_ENDIAN_LITTLE },
{ "svx", 0, SF_FORMAT_SVX },
{ "nist", 0, SF_FORMAT_NIST },
{ "sph", 0, SF_FORMAT_NIST },
{ "voc", 0, SF_FORMAT_VOC },
{ "ircam", 0, SF_FORMAT_IRCAM },
{ "sf", 0, SF_FORMAT_IRCAM },
{ "w64", 0, SF_FORMAT_W64 },
{ "mat", 0, SF_FORMAT_MAT4 },
{ "mat4", 0, SF_FORMAT_MAT4 },
{ "mat5", 0, SF_FORMAT_MAT5 },
{ "pvf", 0, SF_FORMAT_PVF },
{ "xi", 0, SF_FORMAT_XI },
{ "htk", 0, SF_FORMAT_HTK },
{ "sds", 0, SF_FORMAT_SDS },
{ "avr", 0, SF_FORMAT_AVR },
{ "wavex", 0, SF_FORMAT_WAVEX },
{ "sd2", 0, SF_FORMAT_SD2 },
{ "flac", 0, SF_FORMAT_FLAC },
{ "caf", 0, SF_FORMAT_CAF },
{ "wve", 0, SF_FORMAT_WVE },
{ "prc", 0, SF_FORMAT_WVE },
{ "oga", 0, SF_FORMAT_OGG },
{ "ogg", 0, SF_FORMAT_OGG | SF_FORMAT_VORBIS },
{ "opus", 0, SF_FORMAT_OGG | SF_FORMAT_OPUS },
{ "mpc", 0, SF_FORMAT_MPC2K },
{ "rf64", 0, SF_FORMAT_RF64 },
{ "mp3", 0, SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III },
} ; /* format_map */
int
sfe_file_type_of_ext (const char *str, int format)
{ char buffer [16], *cptr ;
int k ;
format &= SF_FORMAT_SUBMASK ;
if ((cptr = strrchr (str, '.')) == NULL)
return 0 ;
strncpy (buffer, cptr + 1, 15) ;
buffer [15] = 0 ;
for (k = 0 ; buffer [k] ; k++)
buffer [k] = tolower ((buffer [k])) ;
for (k = 0 ; k < (int) (sizeof (format_map) / sizeof (format_map [0])) ; k++)
{ if ((format_map [k].len > 0 && strncmp (buffer, format_map [k].ext, format_map [k].len) == 0) ||
(strcmp (buffer, format_map [k].ext) == 0))
{ if (format_map [k].format & SF_FORMAT_SUBMASK)
return format_map [k].format ;
else
return format_map [k].format | format ;
} ;
} ;
/* Default if all the above fails. */
return (SF_FORMAT_WAV | SF_FORMAT_PCM_24) ;
} /* sfe_file_type_of_ext */
void
sfe_dump_format_map (void)
{ SF_FORMAT_INFO info ;
int k ;
for (k = 0 ; k < ARRAY_LEN (format_map) ; k++)
{ info.format = format_map [k].format ;
sf_command (NULL, SFC_GET_FORMAT_INFO, &info, sizeof (info)) ;
printf (" %-10s : %s", format_map [k].ext, info.name == NULL ? "????" : info.name) ;
if (format_map [k].format & SF_FORMAT_SUBMASK)
{ info.format = format_map [k].format & SF_FORMAT_SUBMASK ;
sf_command (NULL, SFC_GET_FORMAT_INFO, &info, sizeof (info)) ;
printf (" %s", info.name == NULL ? "????" : info.name) ;
} ;
putchar ('\n') ;
} ;
} /* sfe_dump_format_map */
const char *
program_name (const char * argv0)
{ const char * tmp ;
tmp = strrchr (argv0, '/') ;
argv0 = tmp ? tmp + 1 : argv0 ;
/* Remove leading libtool name mangling. */
if (strstr (argv0, "lt-") == argv0)
return argv0 + 3 ;
return argv0 ;
} /* program_name */
const char *
sfe_endian_name (int format)
{
switch (format & SF_FORMAT_ENDMASK)
{ case SF_ENDIAN_FILE : return "file" ;
case SF_ENDIAN_LITTLE : return "little" ;
case SF_ENDIAN_BIG : return "big" ;
case SF_ENDIAN_CPU : return "cpu" ;
default : break ;
} ;
return "unknown" ;
} /* sfe_endian_name */
const char *
sfe_container_name (int format)
{
switch (format & SF_FORMAT_TYPEMASK)
{ case SF_FORMAT_WAV : return "WAV" ;
case SF_FORMAT_AIFF : return "AIFF" ;
case SF_FORMAT_AU : return "AU" ;
case SF_FORMAT_RAW : return "RAW" ;
case SF_FORMAT_PAF : return "PAF" ;
case SF_FORMAT_SVX : return "SVX" ;
case SF_FORMAT_NIST : return "NIST" ;
case SF_FORMAT_VOC : return "VOC" ;
case SF_FORMAT_IRCAM : return "IRCAM" ;
case SF_FORMAT_W64 : return "W64" ;
case SF_FORMAT_MAT4 : return "MAT4" ;
case SF_FORMAT_MAT5 : return "MAT5" ;
case SF_FORMAT_PVF : return "PVF" ;
case SF_FORMAT_XI : return "XI" ;
case SF_FORMAT_HTK : return "HTK" ;
case SF_FORMAT_SDS : return "SDS" ;
case SF_FORMAT_AVR : return "AVR" ;
case SF_FORMAT_WAVEX : return "WAVEX" ;
case SF_FORMAT_SD2 : return "SD2" ;
case SF_FORMAT_FLAC : return "FLAC" ;
case SF_FORMAT_CAF : return "CAF" ;
case SF_FORMAT_WVE : return "WVE" ;
case SF_FORMAT_OGG : return "OGG" ;
case SF_FORMAT_MPC2K : return "MPC2K" ;
case SF_FORMAT_RF64 : return "RF64" ;
case SF_FORMAT_MPEG : return "MPEG" ;
default : break ;
} ;
return "unknown" ;
} /* sfe_container_name */
const char *
sfe_codec_name (int format)
{
switch (format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_PCM_S8 : return "signed 8 bit PCM" ;
case SF_FORMAT_PCM_16 : return "16 bit PCM" ;
case SF_FORMAT_PCM_24 : return "24 bit PCM" ;
case SF_FORMAT_PCM_32 : return "32 bit PCM" ;
case SF_FORMAT_PCM_U8 : return "unsigned 8 bit PCM" ;
case SF_FORMAT_FLOAT : return "32 bit float" ;
case SF_FORMAT_DOUBLE : return "64 bit double" ;
case SF_FORMAT_ULAW : return "u-law" ;
case SF_FORMAT_ALAW : return "a-law" ;
case SF_FORMAT_IMA_ADPCM : return "IMA ADPCM" ;
case SF_FORMAT_MS_ADPCM : return "MS ADPCM" ;
case SF_FORMAT_GSM610 : return "gsm610" ;
case SF_FORMAT_VOX_ADPCM : return "Vox ADPCM" ;
case SF_FORMAT_G721_32 : return "g721 32kbps" ;
case SF_FORMAT_G723_24 : return "g723 24kbps" ;
case SF_FORMAT_G723_40 : return "g723 40kbps" ;
case SF_FORMAT_DWVW_12 : return "12 bit DWVW" ;
case SF_FORMAT_DWVW_16 : return "16 bit DWVW" ;
case SF_FORMAT_DWVW_24 : return "14 bit DWVW" ;
case SF_FORMAT_DWVW_N : return "DWVW" ;
case SF_FORMAT_DPCM_8 : return "8 bit DPCM" ;
case SF_FORMAT_DPCM_16 : return "16 bit DPCM" ;
case SF_FORMAT_VORBIS : return "Vorbis" ;
case SF_FORMAT_ALAC_16 : return "16 bit ALAC" ;
case SF_FORMAT_ALAC_20 : return "20 bit ALAC" ;
case SF_FORMAT_ALAC_24 : return "24 bit ALAC" ;
case SF_FORMAT_ALAC_32 : return "32 bit ALAC" ;
case SF_FORMAT_OPUS : return "Opus" ;
case SF_FORMAT_MPEG_LAYER_I : return "MPEG layer 1" ;
case SF_FORMAT_MPEG_LAYER_II : return "MPEG layer 2" ;
case SF_FORMAT_MPEG_LAYER_III : return "MPEG layer 3" ;
default : break ;
} ;
return "unknown" ;
} /* sfe_codec_name */

View file

@ -0,0 +1,82 @@
/*
** Copyright (C) 1999-2013 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof (x [0])))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef struct
{ const char * title ;
const char * copyright ;
const char * artist ;
const char * comment ;
const char * date ;
const char * album ;
const char * license ;
/* Stuff to go in the 'bext' chunk of WAV files. */
int has_bext_fields ;
int coding_hist_append ;
const char * description ;
const char * originator ;
const char * originator_reference ;
const char * origination_date ;
const char * origination_time ;
const char * umid ;
const char * loudness_value ;
const char * loudness_range ;
const char * max_true_peak_level ;
const char * max_momentary_loudness ;
const char * max_shortterm_loudness ;
const char * coding_history ;
const char * time_ref ;
} METADATA_INFO ;
typedef SF_BROADCAST_INFO_VAR (2048) SF_BROADCAST_INFO_2K ;
void sfe_apply_metadata_changes (const char * filenames [2], const METADATA_INFO * info) ;
int sfe_copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels, int normalize) ;
void sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) ;
int sfe_file_type_of_ext (const char *filename, int format) ;
void sfe_dump_format_map (void) ;
const char * program_name (const char * argv0) ;
const char * sfe_endian_name (int format) ;
const char * sfe_container_name (int format) ;
const char * sfe_codec_name (int format) ;

View file

@ -0,0 +1,155 @@
/*
** Copyright (C) 2008-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2008 Conrad Parker <conrad@metadecks.org>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <sndfile.h>
#include "common.h"
/* Length of comparison data buffers in units of items */
#define BUFLEN 65536
static const char * progname = NULL ;
static char * filename1 = NULL, * filename2 = NULL ;
static int
comparison_error (const char * what, sf_count_t frame_offset)
{ char buffer [128] ;
if (frame_offset >= 0)
snprintf (buffer, sizeof (buffer), " (at frame offset %" PRId64 ")", frame_offset) ;
else
buffer [0] = 0 ;
printf ("%s: %s of files %s and %s differ%s.\n", progname, what, filename1, filename2, buffer) ;
return 1 ;
} /* comparison_error */
static int
compare (void)
{
double buf1 [BUFLEN], buf2 [BUFLEN] ;
SF_INFO sfinfo1, sfinfo2 ;
SNDFILE * sf1 = NULL, * sf2 = NULL ;
sf_count_t items, i, nread1, nread2, offset = 0 ;
int retval = 0 ;
memset (&sfinfo1, 0, sizeof (SF_INFO)) ;
sf1 = sf_open (filename1, SFM_READ, &sfinfo1) ;
if (sf1 == NULL)
{ printf ("Error opening %s.\n", filename1) ;
retval = 1 ;
goto out ;
} ;
memset (&sfinfo2, 0, sizeof (SF_INFO)) ;
sf2 = sf_open (filename2, SFM_READ, &sfinfo2) ;
if (sf2 == NULL)
{ printf ("Error opening %s.\n", filename2) ;
retval = 1 ;
goto out ;
} ;
if (sfinfo1.samplerate != sfinfo2.samplerate)
{ retval = comparison_error ("Samplerates", -1) ;
goto out ;
} ;
if (sfinfo1.channels != sfinfo2.channels)
{ retval = comparison_error ("Number of channels", -1) ;
goto out ;
} ;
/* Calculate the framecount that will fit in our data buffers */
items = BUFLEN / sfinfo1.channels ;
while ((nread1 = sf_readf_double (sf1, buf1, items)) > 0)
{ nread2 = sf_readf_double (sf2, buf2, nread1) ;
if (nread2 != nread1)
{ retval = comparison_error ("PCM data lengths", -1) ;
goto out ;
} ;
for (i = 0 ; i < nread1 * sfinfo1.channels ; i++)
{ if (buf1 [i] != buf2 [i])
{ retval = comparison_error ("PCM data", offset + i / sfinfo1.channels) ;
goto out ;
} ;
} ;
offset += nread1 ;
} ;
if ((nread2 = sf_readf_double (sf2, buf2, items)) != 0)
{ retval = comparison_error ("PCM data lengths", -1) ;
goto out ;
} ;
out :
sf_close (sf1) ;
sf_close (sf2) ;
return retval ;
} /* compare */
static void
usage_exit (void)
{
printf ("Usage : %s <filename> <filename>\n", progname) ;
printf (" Compare the PCM data of two sound files.\n\n") ;
printf ("Using %s.\n\n", sf_version_string ()) ;
exit (1) ;
} /* usage_exit */
int
main (int argc, char *argv [])
{
progname = program_name (argv [0]) ;
if (argc != 3)
usage_exit () ;
filename1 = argv [argc - 2] ;
filename2 = argv [argc - 1] ;
if (strcmp (filename1, filename2) == 0)
{ printf ("Error : Input filenames are the same.\n\n") ;
usage_exit () ;
} ;
return compare () ;
} /* main */

View file

@ -0,0 +1,170 @@
/*
** Copyright (C) 1999-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN (1 << 16)
static void concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels) ;
static void concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels) ;
static void
usage_exit (const char *progname)
{
printf ("\nUsage : %s <infile1> <infile2> ... <outfile>\n\n", progname) ;
puts (
" Create a new output file <outfile> containing the concatenated\n"
" audio data from froms <infile1> <infile2> ....\n"
"\n"
" The joined file will be encoded in the same format as the data\n"
" in infile1, with all the data in subsequent files automatically\n"
" converted to the correct encoding.\n"
"\n"
" The only restriction is that the two files must have the same\n"
" number of channels.\n"
) ;
exit (1) ;
} /* usage_exit */
int
main (int argc, char *argv [])
{ const char *progname, *outfilename ;
SNDFILE *outfile, **infiles ;
SF_INFO sfinfo_out, sfinfo_in ;
void (*func) (SNDFILE*, SNDFILE*, int) ;
int k ;
progname = program_name (argv [0]) ;
if (argc < 4)
usage_exit (progname) ;
argv ++ ;
argc -- ;
argc -- ;
outfilename = argv [argc] ;
if ((infiles = calloc (argc, sizeof (SNDFILE*))) == NULL)
{ printf ("\nError : Malloc failed.\n\n") ;
exit (1) ;
} ;
memset (&sfinfo_in, 0, sizeof (sfinfo_in)) ;
if ((infiles [0] = sf_open (argv [0], SFM_READ, &sfinfo_in)) == NULL)
{ printf ("\nError : failed to open file '%s'.\n\n", argv [0]) ;
exit (1) ;
} ;
sfinfo_out = sfinfo_in ;
for (k = 1 ; k < argc ; k++)
{ if ((infiles [k] = sf_open (argv [k], SFM_READ, &sfinfo_in)) == NULL)
{ printf ("\nError : failed to open file '%s'.\n\n", argv [k]) ;
exit (1) ;
} ;
if (sfinfo_in.channels != sfinfo_out.channels)
{ printf ("\nError : File '%s' has %d channels (should have %d).\n\n", argv [k], sfinfo_in.channels, sfinfo_out.channels) ;
exit (1) ;
} ;
} ;
if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo_out)) == NULL)
{ printf ("\nError : Not able to open input file %s.\n", outfilename) ;
puts (sf_strerror (NULL)) ;
exit (1) ;
} ;
if ((sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE ||
(sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT)
func = concat_data_fp ;
else
func = concat_data_int ;
for (k = 0 ; k < argc ; k++)
{ func (outfile, infiles [k], sfinfo_out.channels) ;
sf_close (infiles [k]) ;
} ;
sf_close (outfile) ;
free (infiles) ;
return 0 ;
} /* main */
static void
concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels)
{ static double data [BUFFER_LEN] ;
int frames, readcount ;
frames = BUFFER_LEN / channels ;
readcount = frames ;
sf_seek (wfile, 0, SEEK_END) ;
while (readcount > 0)
{ readcount = (int) sf_readf_double (rofile, data, frames) ;
sf_writef_double (wfile, data, readcount) ;
} ;
return ;
} /* concat_data_fp */
static void
concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels)
{ static int data [BUFFER_LEN] ;
int frames, readcount ;
frames = BUFFER_LEN / channels ;
readcount = frames ;
sf_seek (wfile, 0, SEEK_END) ;
while (readcount > 0)
{ readcount = (int) sf_readf_int (rofile, data, frames) ;
sf_writef_int (wfile, data, readcount) ;
} ;
return ;
} /* concat_data_int */

View file

@ -0,0 +1,410 @@
/*
** Copyright (C) 1999-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sndfile.h>
#include "common.h"
typedef struct
{ char *infilename, *outfilename ;
SF_INFO infileinfo, outfileinfo ;
} OptionData ;
static void copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels) ;
static void
usage_exit (const char *progname)
{
printf ("\nUsage : %s [options] [encoding] <input file> <output file>\n", progname) ;
puts ("\n"
" where [option] may be:\n\n"
" -override-sample-rate=X : force sample rate of input to X\n"
" -endian=little : force output file to little endian data\n"
" -endian=big : force output file to big endian data\n"
" -endian=cpu : force output file same endian-ness as the CPU\n"
" -normalize : normalize the data in the output file\n"
) ;
puts (
" where [encoding] may be one of the following:\n\n"
" -pcms8 : signed 8 bit pcm\n"
" -pcmu8 : unsigned 8 bit pcm\n"
" -pcm16 : 16 bit pcm\n"
" -pcm24 : 24 bit pcm\n"
" -pcm32 : 32 bit pcm\n"
" -float32 : 32 bit floating point\n"
" -float64 : 64 bit floating point\n"
" -ulaw : ULAW\n"
" -alaw : ALAW\n"
" -alac16 : 16 bit ALAC (CAF only)\n"
" -alac20 : 20 bit ALAC (CAF only)\n"
" -alac24 : 24 bit ALAC (CAF only)\n"
" -alac32 : 32 bit ALAC (CAF only)\n"
" -ima-adpcm : IMA ADPCM (WAV only)\n"
" -ms-adpcm : MS ADPCM (WAV only)\n"
" -gsm610 : GSM6.10 (WAV only)\n"
" -dwvw12 : 12 bit DWVW (AIFF only)\n"
" -dwvw16 : 16 bit DWVW (AIFF only)\n"
" -dwvw24 : 24 bit DWVW (AIFF only)\n"
" -vorbis : Vorbis (OGG only)\n"
" -opus : Opus (OGG only)\n"
) ;
puts (
" If no encoding is specified, the program will try to use the encoding\n"
" of the input file in the output file. This will not always work as\n"
" most container formats (eg WAV, AIFF etc) only support a small subset\n"
" of codec formats (eg 16 bit PCM, a-law, Vorbis etc).\n"
) ;
puts (
" The format of the output file is determined by the file extension of the\n"
" output file name. The following extensions are currently understood:\n"
) ;
sfe_dump_format_map () ;
puts ("") ;
exit (1) ;
} /* usage_exit */
static void
report_format_error_exit (const char * argv0, SF_INFO * sfinfo)
{ int old_format = sfinfo->format ;
int endian = sfinfo->format & SF_FORMAT_ENDMASK ;
int channels = sfinfo->channels ;
sfinfo->format = old_format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ;
if (endian && sf_format_check (sfinfo))
{ printf ("Error : output file format does not support %s endian-ness.\n", sfe_endian_name (endian)) ;
exit (1) ;
} ;
sfinfo->channels = 1 ;
if (sf_format_check (sfinfo))
{ printf ("Error : output file format does not support %d channels.\n", channels) ;
exit (1) ;
} ;
printf ("\n"
"Error : output file format is invalid.\n"
"The '%s' container does not support '%s' codec data.\n"
"Run '%s --help' for clues.\n\n",
sfe_container_name (sfinfo->format), sfe_codec_name (sfinfo->format), program_name (argv0)) ;
exit (1) ;
} /* report_format_error_exit */
int
main (int argc, char * argv [])
{ const char *progname, *infilename, *outfilename ;
SNDFILE *infile = NULL, *outfile = NULL ;
SF_INFO sfinfo ;
int k, outfilemajor, outfileminor = 0, infileminor ;
int override_sample_rate = 0 ; /* assume no sample rate override. */
int endian = SF_ENDIAN_FILE, normalize = SF_FALSE ;
progname = program_name (argv [0]) ;
if (argc < 3 || argc > 5)
usage_exit (progname) ;
infilename = argv [argc-2] ;
outfilename = argv [argc-1] ;
if (strcmp (infilename, outfilename) == 0)
{ printf ("Error : Input and output filenames are the same.\n\n") ;
usage_exit (progname) ;
} ;
if (strlen (infilename) > 1 && infilename [0] == '-')
{ printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ;
usage_exit (progname) ;
} ;
if (outfilename [0] == '-')
{ printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ;
usage_exit (progname) ;
} ;
for (k = 1 ; k < argc - 2 ; k++)
{ if (! strcmp (argv [k], "-pcms8"))
{ outfileminor = SF_FORMAT_PCM_S8 ;
continue ;
} ;
if (! strcmp (argv [k], "-pcmu8"))
{ outfileminor = SF_FORMAT_PCM_U8 ;
continue ;
} ;
if (! strcmp (argv [k], "-pcm16"))
{ outfileminor = SF_FORMAT_PCM_16 ;
continue ;
} ;
if (! strcmp (argv [k], "-pcm24"))
{ outfileminor = SF_FORMAT_PCM_24 ;
continue ;
} ;
if (! strcmp (argv [k], "-pcm32"))
{ outfileminor = SF_FORMAT_PCM_32 ;
continue ;
} ;
if (! strcmp (argv [k], "-float32"))
{ outfileminor = SF_FORMAT_FLOAT ;
continue ;
} ;
if (! strcmp (argv [k], "-float64"))
{ outfileminor = SF_FORMAT_DOUBLE ;
continue ;
} ;
if (! strcmp (argv [k], "-ulaw"))
{ outfileminor = SF_FORMAT_ULAW ;
continue ;
} ;
if (! strcmp (argv [k], "-alaw"))
{ outfileminor = SF_FORMAT_ALAW ;
continue ;
} ;
if (! strcmp (argv [k], "-alac16"))
{ outfileminor = SF_FORMAT_ALAC_16 ;
continue ;
} ;
if (! strcmp (argv [k], "-alac20"))
{ outfileminor = SF_FORMAT_ALAC_20 ;
continue ;
} ;
if (! strcmp (argv [k], "-alac24"))
{ outfileminor = SF_FORMAT_ALAC_24 ;
continue ;
} ;
if (! strcmp (argv [k], "-alac32"))
{ outfileminor = SF_FORMAT_ALAC_32 ;
continue ;
} ;
if (! strcmp (argv [k], "-ima-adpcm"))
{ outfileminor = SF_FORMAT_IMA_ADPCM ;
continue ;
} ;
if (! strcmp (argv [k], "-ms-adpcm"))
{ outfileminor = SF_FORMAT_MS_ADPCM ;
continue ;
} ;
if (! strcmp (argv [k], "-gsm610"))
{ outfileminor = SF_FORMAT_GSM610 ;
continue ;
} ;
if (! strcmp (argv [k], "-dwvw12"))
{ outfileminor = SF_FORMAT_DWVW_12 ;
continue ;
} ;
if (! strcmp (argv [k], "-dwvw16"))
{ outfileminor = SF_FORMAT_DWVW_16 ;
continue ;
} ;
if (! strcmp (argv [k], "-dwvw24"))
{ outfileminor = SF_FORMAT_DWVW_24 ;
continue ;
} ;
if (! strcmp (argv [k], "-vorbis"))
{ outfileminor = SF_FORMAT_VORBIS ;
continue ;
} ;
if (! strcmp (argv [k], "-opus"))
{ outfileminor = SF_FORMAT_OPUS ;
continue ;
} ;
if (strstr (argv [k], "-override-sample-rate=") == argv [k])
{ const char *ptr ;
ptr = argv [k] + strlen ("-override-sample-rate=") ;
override_sample_rate = atoi (ptr) ;
continue ;
} ;
if (! strcmp (argv [k], "-endian=little"))
{ endian = SF_ENDIAN_LITTLE ;
continue ;
} ;
if (! strcmp (argv [k], "-endian=big"))
{ endian = SF_ENDIAN_BIG ;
continue ;
} ;
if (! strcmp (argv [k], "-endian=cpu"))
{ endian = SF_ENDIAN_CPU ;
continue ;
} ;
if (! strcmp (argv [k], "-endian=file"))
{ endian = SF_ENDIAN_FILE ;
continue ;
} ;
if (! strcmp (argv [k], "-normalize"))
{ normalize = SF_TRUE ;
continue ;
} ;
printf ("Error : Not able to decode argument '%s'.\n", argv [k]) ;
exit (1) ;
} ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((infile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Not able to open input file %s.\n", infilename) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
/* Update sample rate if forced to something else. */
if (override_sample_rate)
sfinfo.samplerate = override_sample_rate ;
infileminor = sfinfo.format & SF_FORMAT_SUBMASK ;
if ((sfinfo.format = sfe_file_type_of_ext (outfilename, sfinfo.format)) == 0)
{ printf ("Error : Not able to determine output file type for %s.\n", outfilename) ;
return 1 ;
} ;
outfilemajor = sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_ENDMASK) ;
if (outfileminor == 0)
outfileminor = sfinfo.format & SF_FORMAT_SUBMASK ;
if (outfileminor != 0)
sfinfo.format = outfilemajor | outfileminor ;
else
sfinfo.format = outfilemajor | (sfinfo.format & SF_FORMAT_SUBMASK) ;
sfinfo.format |= endian ;
if ((sfinfo.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_XI)
switch (sfinfo.format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_PCM_16 :
sfinfo.format = outfilemajor | SF_FORMAT_DPCM_16 ;
break ;
case SF_FORMAT_PCM_S8 :
case SF_FORMAT_PCM_U8 :
sfinfo.format = outfilemajor | SF_FORMAT_DPCM_8 ;
break ;
} ;
if (sf_format_check (&sfinfo) == 0)
{ sf_close (infile) ;
report_format_error_exit (argv [0], &sfinfo) ;
} ;
if ((sfinfo.format & SF_FORMAT_SUBMASK) == SF_FORMAT_GSM610 && sfinfo.samplerate != 8000)
{ printf (
"WARNING: GSM 6.10 data format only supports 8kHz sample rate. The converted\n"
"ouput file will contain the input data converted to the GSM 6.10 data format\n"
"but not re-sampled.\n"
) ;
} ;
/* Open the output file. */
if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo)) == NULL)
{ printf ("Not able to open output file %s : %s\n", outfilename, sf_strerror (NULL)) ;
return 1 ;
} ;
/* Copy the metadata */
copy_metadata (outfile, infile, sfinfo.channels) ;
if (normalize
|| (outfileminor == SF_FORMAT_DOUBLE) || (outfileminor == SF_FORMAT_FLOAT)
|| (infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT)
|| (infileminor == SF_FORMAT_OPUS) || (outfileminor == SF_FORMAT_OPUS)
|| (infileminor == SF_FORMAT_VORBIS) || (outfileminor == SF_FORMAT_VORBIS)
|| (infileminor == SF_FORMAT_MPEG_LAYER_I)
|| (infileminor == SF_FORMAT_MPEG_LAYER_II)
|| (infileminor == SF_FORMAT_MPEG_LAYER_III) || (outfileminor == SF_FORMAT_MPEG_LAYER_III))
{ if (sfe_copy_data_fp (outfile, infile, sfinfo.channels, normalize) != 0)
{ printf ("Error : Not able to decode input file %s.\n", infilename) ;
return 1 ;
} ;
}
else
sfe_copy_data_int (outfile, infile, sfinfo.channels) ;
sf_close (infile) ;
sf_close (outfile) ;
return 0 ;
} /* main */
static void
copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels)
{ SF_INSTRUMENT inst ;
SF_CUES cues ;
SF_BROADCAST_INFO_2K binfo ;
const char *str ;
int k, chanmap [256] ;
for (k = SF_STR_FIRST ; k <= SF_STR_LAST ; k++)
{ str = sf_get_string (infile, k) ;
if (str != NULL)
sf_set_string (outfile, k, str) ;
} ;
memset (&inst, 0, sizeof (inst)) ;
memset (&cues, 0, sizeof (cues)) ;
memset (&binfo, 0, sizeof (binfo)) ;
if (channels < ARRAY_LEN (chanmap))
{ int size = channels * sizeof (chanmap [0]) ;
if (sf_command (infile, SFC_GET_CHANNEL_MAP_INFO, chanmap, size) == SF_TRUE)
sf_command (outfile, SFC_SET_CHANNEL_MAP_INFO, chanmap, size) ;
} ;
if (sf_command (infile, SFC_GET_CUE, &cues, sizeof (cues)) == SF_TRUE)
sf_command (outfile, SFC_SET_CUE, &cues, sizeof (cues)) ;
if (sf_command (infile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE)
sf_command (outfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) ;
if (sf_command (infile, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == SF_TRUE)
sf_command (outfile, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) ;
} /* copy_metadata */

View file

@ -0,0 +1,222 @@
/*
** Copyright (C) 2009-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN 4096
#define MAX_CHANNELS 16
typedef struct
{ SNDFILE * infile ;
SNDFILE * outfile [MAX_CHANNELS] ;
union
{ double d [MAX_CHANNELS * BUFFER_LEN] ;
int i [MAX_CHANNELS * BUFFER_LEN] ;
} din ;
union
{ double d [BUFFER_LEN] ;
int i [BUFFER_LEN] ;
} dout ;
int channels ;
} STATE ;
static void usage_exit (void) ;
static void deinterleave_int (STATE * state) ;
static void deinterleave_double (STATE * state) ;
int
main (int argc, char **argv)
{ STATE *state = NULL ;
SF_INFO sfinfo ;
char pathname [512], ext [32], *cptr ;
int ch, double_split, ret = 1 ;
if (argc != 2)
{ if (argc != 1)
puts ("\nError : need a single input file.\n") ;
usage_exit () ;
goto cleanup ;
} ;
state = calloc (1, sizeof (*state)) ;
if (!state)
{ printf ("\nError : Out of memory.\n") ;
goto cleanup ;
} ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((state->infile = sf_open (argv [1], SFM_READ, &sfinfo)) == NULL)
{ printf ("\nError : Not able to open input file '%s'\n%s\n", argv [1], sf_strerror (NULL)) ;
goto cleanup ;
} ;
if (sfinfo.channels < 2)
{ printf ("\nError : Input file '%s' only has one channel.\n", argv [1]) ;
goto cleanup ;
} ;
if (sfinfo.channels > MAX_CHANNELS)
{ printf ("\nError : Input file '%s' has too many (%d) channels. Limit is %d.\n",
argv [1], sfinfo.channels, MAX_CHANNELS) ;
goto cleanup ;
} ;
state->channels = sfinfo.channels ;
sfinfo.channels = 1 ;
if (snprintf (pathname, sizeof (pathname), "%s", argv [1]) > (int) sizeof (pathname))
{ printf ("\nError : Length of provided filename '%s' exceeds MAX_PATH (%d).\n", argv [1], (int) sizeof (pathname)) ;
goto cleanup ;
} ;
if ((cptr = strrchr (pathname, '.')) == NULL)
ext [0] = 0 ;
else
{ snprintf (ext, sizeof (ext), "%s", cptr) ;
cptr [0] = 0 ;
} ;
printf ("Input file : %s\n", pathname) ;
puts ("Output files :") ;
for (ch = 0 ; ch < state->channels ; ch++)
{ char filename [520] ;
size_t count ;
count = snprintf (filename, sizeof (filename), "%s_%02d%s", pathname, ch, ext) ;
if (count >= sizeof (filename))
{ printf ("File name truncated to %s\n", filename) ;
} ;
if ((state->outfile [ch] = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)
{ printf ("Not able to open output file '%s'\n%s\n", filename, sf_strerror (NULL)) ;
goto cleanup ;
} ;
printf (" %s\n", filename) ;
} ;
switch (sfinfo.format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_FLOAT :
case SF_FORMAT_DOUBLE :
case SF_FORMAT_VORBIS :
double_split = 1 ;
break ;
default :
double_split = 0 ;
break ;
} ;
if (double_split)
deinterleave_double (state) ;
else
deinterleave_int (state) ;
ret = 0 ;
cleanup :
if (state != NULL)
{ sf_close (state->infile) ;
for (ch = 0 ; ch < MAX_CHANNELS ; ch++)
if (state->outfile [ch] != NULL)
sf_close (state->outfile [ch]) ;
} ;
free (state) ;
return ret ;
} /* main */
/*------------------------------------------------------------------------------
*/
static void
usage_exit (void)
{ puts ("\nUsage : sndfile-deinterleave <filename>\n") ;
puts (
"Split a mutli-channel file into a set of mono files.\n"
"\n"
"If the input file is named 'a.wav', the output files will be named\n"
"a_00.wav, a_01.wav and so on.\n"
) ;
printf ("Using %s.\n\n", sf_version_string ()) ;
} /* usage_exit */
static void
deinterleave_int (STATE * state)
{ int read_len ;
int ch, k ;
do
{ read_len = (int) sf_readf_int (state->infile, state->din.i, BUFFER_LEN) ;
for (ch = 0 ; ch < state->channels ; ch ++)
{ for (k = 0 ; k < read_len ; k++)
state->dout.i [k] = state->din.i [k * state->channels + ch] ;
sf_write_int (state->outfile [ch], state->dout.i, read_len) ;
} ;
}
while (read_len > 0) ;
} /* deinterleave_int */
static void
deinterleave_double (STATE * state)
{ int read_len ;
int ch, k ;
do
{ read_len = (int) sf_readf_double (state->infile, state->din.d, BUFFER_LEN) ;
for (ch = 0 ; ch < state->channels ; ch ++)
{ for (k = 0 ; k < read_len ; k++)
state->dout.d [k] = state->din.d [k * state->channels + ch] ;
sf_write_double (state->outfile [ch], state->dout.d, read_len) ;
} ;
}
while (read_len > 0) ;
} /* deinterleave_double */

View file

@ -0,0 +1,529 @@
/*
** Copyright (C) 1999-2019 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <math.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN (1 << 16)
#if (defined (WIN32) || defined (_WIN32))
#include <windows.h>
#endif
static void usage_exit (const char *progname) ;
static void info_dump (const char *filename) ;
static int instrument_dump (const char *filename) ;
static int broadcast_dump (const char *filename) ;
static int chanmap_dump (const char *filename) ;
static int cart_dump (const char *filename) ;
static void total_dump (void) ;
static double total_seconds = 0.0 ;
int
main (int argc, char *argv [])
{ int k ;
if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0)
usage_exit (program_name (argv [0])) ;
if (strcmp (argv [1], "--instrument") == 0)
{ int error = 0 ;
for (k = 2 ; k < argc ; k++)
error += instrument_dump (argv [k]) ;
return error ;
} ;
if (strcmp (argv [1], "--broadcast") == 0)
{ int error = 0 ;
for (k = 2 ; k < argc ; k++)
error += broadcast_dump (argv [k]) ;
return error ;
} ;
if (strcmp (argv [1], "--channel-map") == 0)
{ int error = 0 ;
for (k = 2 ; k < argc ; k++)
error += chanmap_dump (argv [k]) ;
return error ;
} ;
if (strcmp (argv [1], "--cart") == 0)
{ int error = 0 ;
for (k = 2 ; k < argc ; k++)
error += cart_dump (argv [k]) ;
return error ;
} ;
for (k = 1 ; k < argc ; k++)
info_dump (argv [k]) ;
if (argc > 2)
total_dump () ;
return 0 ;
} /* main */
/*==============================================================================
** Print version and usage.
*/
static void
usage_exit (const char *progname)
{ printf ("Usage :\n %s <file> ...\n", progname) ;
printf (" Prints out information about one or more sound files.\n\n") ;
printf (" %s --instrument <file>\n", progname) ;
printf (" Prints out the instrument data for the given file.\n\n") ;
printf (" %s --broadcast <file>\n", progname) ;
printf (" Prints out the broadcast WAV info for the given file.\n\n") ;
printf (" %s --channel-map <file>\n", progname) ;
printf (" Prints out the channel map for the given file.\n\n") ;
printf (" %s --cart <file>\n", progname) ;
printf (" Prints out the cart chunk WAV info for the given file.\n\n") ;
printf ("Using %s.\n\n", sf_version_string ()) ;
#if (defined (_WIN32) || defined (WIN32))
printf ("This is a Unix style command line application which\n"
"should be run in a MSDOS box or Command Shell window.\n\n") ;
printf ("Sleeping for 5 seconds before exiting.\n\n") ;
fflush (stdout) ;
Sleep (5 * 1000) ;
#endif
exit (1) ;
} /* usage_exit */
/*==============================================================================
** Dumping of sndfile info.
*/
static double data [BUFFER_LEN] ;
static double
calc_decibels (SF_INFO * sfinfo, double max)
{ double decibels ;
switch (sfinfo->format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_S8 :
decibels = max / 0x80 ;
break ;
case SF_FORMAT_PCM_16 :
decibels = max / 0x8000 ;
break ;
case SF_FORMAT_PCM_24 :
decibels = max / 0x800000 ;
break ;
case SF_FORMAT_PCM_32 :
decibels = max / 0x80000000 ;
break ;
case SF_FORMAT_FLOAT :
case SF_FORMAT_DOUBLE :
case SF_FORMAT_VORBIS :
case SF_FORMAT_OPUS :
decibels = max / 1.0 ;
break ;
default :
decibels = max / 0x8000 ;
break ;
} ;
return 20.0 * log10 (decibels) ;
} /* calc_decibels */
static const char *
format_duration_str (double seconds)
{ static char str [128] ;
int hrs, min ;
double sec ;
memset (str, 0, sizeof (str)) ;
hrs = (int) (seconds / 3600.0) ;
min = (int) ((seconds - (hrs * 3600.0)) / 60.0) ;
sec = seconds - (hrs * 3600.0) - (min * 60.0) ;
snprintf (str, sizeof (str) - 1, "%02d:%02d:%06.3f", hrs, min, sec) ;
return str ;
} /* format_duration_str */
static const char *
generate_duration_str (SF_INFO *sfinfo)
{
double seconds ;
if (sfinfo->samplerate < 1)
return NULL ;
if (sfinfo->frames / sfinfo->samplerate > 0x7FFFFFFF)
return "unknown" ;
seconds = (1.0 * sfinfo->frames) / sfinfo->samplerate ;
/* Accumulate the total of all known file durations */
total_seconds += seconds ;
return format_duration_str (seconds) ;
} /* generate_duration_str */
static void
info_dump (const char *filename)
{ static char strbuffer [BUFFER_LEN] ;
SNDFILE *file ;
SF_INFO sfinfo ;
double signal_max, decibels ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Not able to open input file %s.\n", filename) ;
fflush (stdout) ;
memset (data, 0, sizeof (data)) ;
sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ;
puts (strbuffer) ;
puts (sf_strerror (NULL)) ;
return ;
} ;
printf ("========================================\n") ;
sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ;
puts (strbuffer) ;
printf ("----------------------------------------\n") ;
printf ("Sample Rate : %d\n", sfinfo.samplerate) ;
if (sfinfo.frames == SF_COUNT_MAX)
printf ("Frames : unknown\n") ;
else
printf ("Frames : %" PRId64 "\n", sfinfo.frames) ;
printf ("Channels : %d\n", sfinfo.channels) ;
printf ("Format : 0x%08X\n", sfinfo.format) ;
printf ("Sections : %d\n", sfinfo.sections) ;
printf ("Seekable : %s\n", (sfinfo.seekable ? "TRUE" : "FALSE")) ;
printf ("Duration : %s\n", generate_duration_str (&sfinfo)) ;
if (sfinfo.frames < 100 * 1024 * 1024)
{ /* Do not use sf_signal_max because it doesn't work for non-seekable files . */
sf_command (file, SFC_CALC_SIGNAL_MAX, &signal_max, sizeof (signal_max)) ;
decibels = calc_decibels (&sfinfo, signal_max) ;
printf ("Signal Max : %g (%4.2f dB)\n", signal_max, decibels) ;
} ;
putchar ('\n') ;
sf_close (file) ;
} /* info_dump */
/*==============================================================================
** Dumping of SF_INSTRUMENT data.
*/
static const char *
str_of_type (int mode)
{ switch (mode)
{ case SF_LOOP_NONE : return "none" ;
case SF_LOOP_FORWARD : return "fwd " ;
case SF_LOOP_BACKWARD : return "back" ;
case SF_LOOP_ALTERNATING : return "alt " ;
default : break ;
} ;
return "????" ;
} /* str_of_mode */
static int
instrument_dump (const char *filename)
{ SNDFILE *file ;
SF_INFO sfinfo ;
SF_INSTRUMENT inst ;
int got_inst, k ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Not able to open input file %s.\n", filename) ;
fflush (stdout) ;
memset (data, 0, sizeof (data)) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
got_inst = sf_command (file, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) ;
sf_close (file) ;
if (got_inst == SF_FALSE)
{ printf ("Error : File '%s' does not contain instrument data.\n\n", filename) ;
return 1 ;
} ;
printf ("Instrument : %s\n\n", filename) ;
printf (" Gain : %d\n", inst.gain) ;
printf (" Base note : %d\n", inst.basenote) ;
printf (" Velocity : %d - %d\n", (int) inst.velocity_lo, (int) inst.velocity_hi) ;
printf (" Key : %d - %d\n", (int) inst.key_lo, (int) inst.key_hi) ;
printf (" Loop points : %d\n", inst.loop_count) ;
for (k = 0 ; k < inst.loop_count ; k++)
printf (" %-2d Mode : %s Start : %6" PRIu32 " End : %6" PRIu32
" Count : %6" PRIu32 "\n", k, str_of_type (inst.loops [k].mode),
inst.loops [k].start, inst.loops [k].end, inst.loops [k].count) ;
putchar ('\n') ;
return 0 ;
} /* instrument_dump */
static int
broadcast_dump (const char *filename)
{ SNDFILE *file ;
SF_INFO sfinfo ;
SF_BROADCAST_INFO_2K bext ;
double time_ref_sec ;
int got_bext ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Not able to open input file %s.\n", filename) ;
fflush (stdout) ;
memset (data, 0, sizeof (data)) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
memset (&bext, 0, sizeof (SF_BROADCAST_INFO_2K)) ;
got_bext = sf_command (file, SFC_GET_BROADCAST_INFO, &bext, sizeof (bext)) ;
sf_close (file) ;
if (got_bext == SF_FALSE)
{ printf ("Error : File '%s' does not contain broadcast information.\n\n", filename) ;
return 1 ;
} ;
/*
** From : http://www.ebu.ch/en/technical/publications/userguides/bwf_user_guide.php
**
** Time Reference:
** This field is a count from midnight in samples to the first sample
** of the audio sequence.
*/
time_ref_sec = ((pow (2.0, 32) * bext.time_reference_high) + (1.0 * bext.time_reference_low)) / sfinfo.samplerate ;
printf ("Description : %.*s\n", (int) sizeof (bext.description), bext.description) ;
printf ("Originator : %.*s\n", (int) sizeof (bext.originator), bext.originator) ;
printf ("Origination ref : %.*s\n", (int) sizeof (bext.originator_reference), bext.originator_reference) ;
printf ("Origination date : %.*s\n", (int) sizeof (bext.origination_date), bext.origination_date) ;
printf ("Origination time : %.*s\n", (int) sizeof (bext.origination_time), bext.origination_time) ;
if (bext.time_reference_high == 0 && bext.time_reference_low == 0)
printf ("Time ref : 0\n") ;
else
printf ("Time ref : 0x%x%08x (%.6f seconds)\n", bext.time_reference_high, bext.time_reference_low, time_ref_sec) ;
printf ("BWF version : %d\n", bext.version) ;
if (bext.version >= 1)
printf ("UMID : %.*s\n", (int) sizeof (bext.umid), bext.umid) ;
if (bext.version >= 2)
{ /* 0x7fff shall be used to designate an unused value */
/* valid range: -99.99 .. 99.99 */
printf ("Loudness value : %6.2f LUFS\n", bext.loudness_value / 100.0) ;
/* valid range: 0.00 .. 99.99 */
printf ("Loudness range : %6.2f LU\n", bext.loudness_range / 100.0) ;
/* valid range: -99.99 .. 99.99 */
printf ("Max. true peak level : %6.2f dBTP\n", bext.max_true_peak_level / 100.0) ;
printf ("Max. momentary loudness : %6.2f LUFS\n", bext.max_momentary_loudness / 100.0) ;
printf ("Max. short term loudness : %6.2f LUFS\n", bext.max_shortterm_loudness / 100.0) ;
} ;
printf ("Coding history : %.*s\n", bext.coding_history_size, bext.coding_history) ;
return 0 ;
} /* broadcast_dump */
static int
chanmap_dump (const char *filename)
{ SNDFILE *file ;
SF_INFO sfinfo ;
int * channel_map ;
int got_chanmap, k ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Not able to open input file %s.\n", filename) ;
fflush (stdout) ;
memset (data, 0, sizeof (data)) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
if ((channel_map = calloc (sfinfo.channels, sizeof (int))) == NULL)
{ printf ("Error : malloc failed.\n\n") ;
return 1 ;
} ;
got_chanmap = sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map, sfinfo.channels * sizeof (int)) ;
sf_close (file) ;
if (got_chanmap == SF_FALSE)
{ printf ("Error : File '%s' does not contain channel map information.\n\n", filename) ;
free (channel_map) ;
return 1 ;
} ;
printf ("File : %s\n\n", filename) ;
puts (" Chan Position") ;
for (k = 0 ; k < sfinfo.channels ; k ++)
{ const char * name ;
#define CASE_NAME(x) case x : name = #x ; break ;
switch (channel_map [k])
{ CASE_NAME (SF_CHANNEL_MAP_INVALID) ;
CASE_NAME (SF_CHANNEL_MAP_MONO) ;
CASE_NAME (SF_CHANNEL_MAP_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_FRONT_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_REAR_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_REAR_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_REAR_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_LFE) ;
CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_SIDE_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_SIDE_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_LEFT) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_RIGHT) ;
CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_CENTER) ;
CASE_NAME (SF_CHANNEL_MAP_MAX) ;
default : name = "default" ;
break ;
} ;
printf (" %3d %s\n", k, name) ;
} ;
putchar ('\n') ;
free (channel_map) ;
return 0 ;
} /* chanmap_dump */
static int
cart_dump (const char *filename)
{ SNDFILE *file ;
SF_INFO sfinfo ;
SF_CART_INFO_VAR (1024) cart ;
int got_cart, k ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
memset (&cart, 0, sizeof (cart)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Not able to open input file %s.\n", filename) ;
fflush (stdout) ;
memset (data, 0, sizeof (data)) ;
puts (sf_strerror (NULL)) ;
return 1 ;
} ;
got_cart = sf_command (file, SFC_GET_CART_INFO, &cart, sizeof (cart)) ;
sf_close (file) ;
if (got_cart == SF_FALSE)
{ printf ("Error : File '%s' does not contain cart information.\n\n", filename) ;
return 1 ;
} ;
printf ("Version : %.*s\n", (int) sizeof (cart.version), cart.version) ;
printf ("Title : %.*s\n", (int) sizeof (cart.title), cart.title) ;
printf ("Artist : %.*s\n", (int) sizeof (cart.artist), cart.artist) ;
printf ("Cut id : %.*s\n", (int) sizeof (cart.cut_id), cart.cut_id) ;
printf ("Category : %.*s\n", (int) sizeof (cart.category), cart.category) ;
printf ("Classification : %.*s\n", (int) sizeof (cart.classification), cart.classification) ;
printf ("Out cue : %.*s\n", (int) sizeof (cart.out_cue), cart.out_cue) ;
printf ("Start date : %.*s\n", (int) sizeof (cart.start_date), cart.start_date) ;
printf ("Start time : %.*s\n", (int) sizeof (cart.start_time), cart.start_time) ;
printf ("End date : %.*s\n", (int) sizeof (cart.end_date), cart.end_date) ;
printf ("End time : %.*s\n", (int) sizeof (cart.end_time), cart.end_time) ;
printf ("App id : %.*s\n", (int) sizeof (cart.producer_app_id), cart.producer_app_id) ;
printf ("App version : %.*s\n", (int) sizeof (cart.producer_app_version), cart.producer_app_version) ;
printf ("User defined : %.*s\n", (int) sizeof (cart.user_def), cart.user_def) ;
printf ("Level ref. : %d\n", cart.level_reference) ;
printf ("Post timers :\n") ;
for (k = 0 ; k < ARRAY_LEN (cart.post_timers) ; k++)
if (cart.post_timers [k].usage [0])
printf (" %d %.*s %d\n", k, (int) sizeof (cart.post_timers [k].usage), cart.post_timers [k].usage, cart.post_timers [k].value) ;
printf ("Reserved : %.*s\n", (int) sizeof (cart.reserved), cart.reserved) ;
printf ("Url : %.*s\n", (int) sizeof (cart.url), cart.url) ;
printf ("Tag text : %.*s\n", cart.tag_text_size, cart.tag_text) ;
return 0 ;
} /* cart_dump */
static void
total_dump (void)
{ printf ("========================================\n") ;
printf ("Total Duration : %s\n", format_duration_str (total_seconds)) ;
} /* total_dump */

View file

@ -0,0 +1,217 @@
/*
** Copyright (C) 2009-2015 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN 4096
#define MAX_INPUTS 16
typedef struct
{ SNDFILE * infile [MAX_INPUTS] ;
SNDFILE * outfile ;
union
{ double d [BUFFER_LEN] ;
int i [BUFFER_LEN] ;
} din ;
union
{ double d [MAX_INPUTS * BUFFER_LEN] ;
int i [MAX_INPUTS * BUFFER_LEN] ;
} dout ;
int channels ;
} STATE ;
static void print_usage (void) ;
static void interleave_int (STATE * state) ;
static void interleave_double (STATE * state) ;
int
main (int argc, char **argv)
{ STATE *state = NULL ;
SF_INFO sfinfo ;
int k, double_merge = 0 ;
int ret = 1 ;
if (argc < 5)
{ if (argc > 1)
puts ("\nError : need at least 2 input files.") ;
print_usage () ;
goto cleanup ;
} ;
if (strcmp (argv [argc - 2], "-o") != 0)
{ puts ("\nError : second last command line parameter should be '-o'.\n") ;
print_usage () ;
goto cleanup ;
} ;
if (argc - 3 > MAX_INPUTS)
{ printf ("\nError : Cannot handle more than %d input channels.\n\n", MAX_INPUTS) ;
goto cleanup ;
} ;
state = calloc (1, sizeof (STATE)) ;
if (state == NULL)
{ puts ("\nError : out of memory.\n") ;
goto cleanup ;
} ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
for (k = 1 ; k < argc - 2 ; k++)
{
if ((state->infile [k - 1] = sf_open (argv [k], SFM_READ, &sfinfo)) == NULL)
{ printf ("\nError : Not able to open input file '%s'\n%s\n", argv [k], sf_strerror (NULL)) ;
goto cleanup ;
} ;
if (sfinfo.channels != 1)
{ printf ("\bError : Input file '%s' should be mono (has %d channels).\n", argv [k], sfinfo.channels) ;
goto cleanup ;
} ;
switch (sfinfo.format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_FLOAT :
case SF_FORMAT_DOUBLE :
case SF_FORMAT_VORBIS :
double_merge = 1 ;
break ;
default :
break ;
} ;
state->channels ++ ;
} ;
sfinfo.channels = state->channels ;
sfinfo.format = sfe_file_type_of_ext (argv [argc - 1], sfinfo.format) ;
if ((state->outfile = sf_open (argv [argc - 1], SFM_WRITE, &sfinfo)) == NULL)
{ printf ("Not able to open output file '%s'\n%s\n", argv [argc - 1], sf_strerror (NULL)) ;
goto cleanup ;
} ;
if (double_merge)
interleave_double (state) ;
else
interleave_int (state) ;
ret = 0 ;
cleanup :
if (state != NULL)
{ for (k = 0 ; k < MAX_INPUTS ; k++)
if (state->infile [k] != NULL)
sf_close (state->infile [k]) ;
sf_close (state->outfile) ;
}
free (state) ;
return ret ;
} /* main */
/*------------------------------------------------------------------------------
*/
static void
print_usage (void)
{ puts ("\nUsage : sndfile-interleave <input 1> <input 2> ... -o <output file>\n") ;
puts ("Merge two or more mono files into a single multi-channel file.\n") ;
printf ("Using %s.\n\n", sf_version_string ()) ;
} /* print_usage */
static void
interleave_int (STATE * state)
{ int max_read_len, read_len ;
int ch, k ;
do
{ max_read_len = 0 ;
for (ch = 0 ; ch < state->channels ; ch ++)
{ read_len = (int) sf_read_int (state->infile [ch], state->din.i, BUFFER_LEN) ;
if (read_len < BUFFER_LEN)
memset (state->din.i + read_len, 0, sizeof (state->din.i [0]) * (BUFFER_LEN - read_len)) ;
for (k = 0 ; k < BUFFER_LEN ; k++)
state->dout.i [k * state->channels + ch] = state->din.i [k] ;
max_read_len = MAX (max_read_len, read_len) ;
} ;
sf_writef_int (state->outfile, state->dout.i, max_read_len) ;
}
while (max_read_len > 0) ;
} /* interleave_int */
static void
interleave_double (STATE * state)
{ int max_read_len, read_len ;
int ch, k ;
do
{ max_read_len = 0 ;
for (ch = 0 ; ch < state->channels ; ch ++)
{ read_len = (int) sf_read_double (state->infile [ch], state->din.d, BUFFER_LEN) ;
if (read_len < BUFFER_LEN)
memset (state->din.d + read_len, 0, sizeof (state->din.d [0]) * (BUFFER_LEN - read_len)) ;
for (k = 0 ; k < BUFFER_LEN ; k++)
state->dout.d [k * state->channels + ch] = state->din.d [k] ;
max_read_len = MAX (max_read_len, read_len) ;
} ;
sf_writef_double (state->outfile, state->dout.d, max_read_len) ;
}
while (max_read_len > 0) ;
} /* interleave_double */

View file

@ -0,0 +1,197 @@
/*
** Copyright (C) 2008-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2008-2010 George Blood Audio
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN (1 << 16)
static void usage_exit (const char *progname, int exit_code) ;
static void process_args (SNDFILE * file, const SF_BROADCAST_INFO_2K * binfo, int argc, char * argv []) ;
int
main (int argc, char *argv [])
{ SNDFILE *file ;
SF_INFO sfinfo ;
SF_BROADCAST_INFO_2K binfo ;
const char *progname ;
const char * filename = NULL ;
int start ;
/* Store the program name. */
progname = program_name (argv [0]) ;
/* Check if we've been asked for help. */
if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0)
usage_exit (progname, 0) ;
if (argv [argc - 1][0] != '-')
{ filename = argv [argc - 1] ;
start = 1 ;
}
else if (argv [1][0] != '-')
{ filename = argv [1] ;
start = 2 ;
}
else
{ printf ("Error : Either the first or the last command line parameter should be a filename.\n\n") ;
exit (1) ;
} ;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL)
{ printf ("Error : Open of file '%s' failed : %s\n\n", filename, sf_strerror (file)) ;
exit (1) ;
} ;
memset (&binfo, 0, sizeof (binfo)) ;
if (sf_command (file, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0)
memset (&binfo, 0, sizeof (binfo)) ;
process_args (file, &binfo, argc - 2, argv + start) ;
sf_close (file) ;
return 0 ;
} /* main */
/*==============================================================================
** Print version and usage.
*/
static void
usage_exit (const char *progname, int exit_code)
{ printf ("\nUsage :\n %s [options] <file>\n\nOptions:\n", progname) ;
puts (
" --bext-description Print the 'bext' description.\n"
" --bext-originator Print the 'bext' originator info.\n"
" --bext-orig-ref Print the 'bext' origination reference.\n"
" --bext-umid Print the 'bext' UMID.\n"
" --bext-orig-date Print the 'bext' origination date.\n"
" --bext-orig-time Print the 'bext' origination time.\n"
" --bext-loudness-value Print the 'bext' loudness value.\n"
" --bext-loudness-range Print the 'bext' loudness range.\n"
" --bext-max-truepeak Print the 'bext' max. true peak level\n"
" --bext-max-momentary Print the 'bext' max. momentary loudness\n"
" --bext-max-shortterm Print the 'bext' max. short term loudness\n"
" --bext-coding-hist Print the 'bext' coding history.\n"
) ;
puts (
" --str-title Print the title metadata.\n"
" --str-copyright Print the copyright metadata.\n"
" --str-artist Print the artist metadata.\n"
" --str-comment Print the comment metadata.\n"
" --str-date Print the creation date metadata.\n"
" --str-album Print the album metadata.\n"
" --str-license Print the license metadata.\n"
) ;
printf ("Using %s.\n\n", sf_version_string ()) ;
exit (exit_code) ;
} /* usage_exit */
static void
process_args (SNDFILE * file, const SF_BROADCAST_INFO_2K * binfo, int argc, char * argv [])
{ const char * str ;
int k, do_all = 0 ;
#define HANDLE_BEXT_ARG(cmd, name, field) \
if (do_all || strcmp (argv [k], cmd) == 0) \
{ printf ("%-22s : %.*s\n", name, (int) sizeof (binfo->field), binfo->field) ; \
if (! do_all) \
continue ; \
} ;
#define HANDLE_BEXT_ARG_INT(cmd, name, field) \
if (do_all || strcmp (argv [k], cmd) == 0) \
{ printf ("%-22s : %6.2f\n", name, binfo->field / 100.0) ; \
if (! do_all) \
continue ; \
} ;
#define HANDLE_STR_ARG(cmd, name, id) \
if (do_all || strcmp (argv [k], cmd) == 0) \
{ str = sf_get_string (file, id) ; \
printf ("%-22s : %s\n", name, str ? str : "") ; \
if (! do_all) continue ; \
} ;
if (argc == 0)
{ do_all = 1 ;
argc = 1 ;
} ;
for (k = 0 ; k < argc ; k++)
{ if (do_all || strcmp (argv [k], "--all") == 0)
do_all = 1 ;
HANDLE_BEXT_ARG ("--bext-description", "Description", description) ;
HANDLE_BEXT_ARG ("--bext-originator", "Originator", originator) ;
HANDLE_BEXT_ARG ("--bext-orig-ref", "Origination ref", originator_reference) ;
HANDLE_BEXT_ARG ("--bext-umid", "UMID", umid) ;
HANDLE_BEXT_ARG ("--bext-orig-date", "Origination date", origination_date) ;
HANDLE_BEXT_ARG ("--bext-orig-time", "Origination time", origination_time) ;
HANDLE_BEXT_ARG_INT ("--bext-loudness-value", "Loudness value", loudness_value) ;
HANDLE_BEXT_ARG_INT ("--bext-loudness-range", "Loudness range", loudness_range) ;
HANDLE_BEXT_ARG_INT ("--bext-max-truepeak", "Max. true peak level", max_true_peak_level) ;
HANDLE_BEXT_ARG_INT ("--bext-max-momentary", "Max. momentary level", max_momentary_loudness) ;
HANDLE_BEXT_ARG_INT ("--bext-max-shortterm", "Max. short term level", max_shortterm_loudness) ;
HANDLE_BEXT_ARG ("--bext-coding-hist", "Coding history", coding_history) ;
HANDLE_STR_ARG ("--str-title", "Name", SF_STR_TITLE) ;
HANDLE_STR_ARG ("--str-copyright", "Copyright", SF_STR_COPYRIGHT) ;
HANDLE_STR_ARG ("--str-artist", "Artist", SF_STR_ARTIST) ;
HANDLE_STR_ARG ("--str-comment", "Comment", SF_STR_COMMENT) ;
HANDLE_STR_ARG ("--str-date", "Create date", SF_STR_DATE) ;
HANDLE_STR_ARG ("--str-album", "Album", SF_STR_ALBUM) ;
HANDLE_STR_ARG ("--str-license", "License", SF_STR_LICENSE) ;
if (! do_all)
{ printf ("Error : Don't know what to do with command line arg '%s'.\n\n", argv [k]) ;
exit (1) ;
} ;
break ;
} ;
return ;
} /* process_args */

View file

@ -0,0 +1,298 @@
/*
** Copyright (C) 2008-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
** Copyright (C) 2008-2010 George Blood Audio
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN (1 << 16)
static void usage_exit (const char *progname, int exit_code) ;
static void missing_param (const char * option) ;
static void read_localtime (struct tm * timedata) ;
static int has_bext_fields_set (const METADATA_INFO * info) ;
int
main (int argc, char *argv [])
{ METADATA_INFO info ;
struct tm timedata ;
const char *progname ;
const char * filenames [2] = { NULL, NULL } ;
char date [128], time [128] ;
int k ;
/* Store the program name. */
progname = program_name (argv [0]) ;
/* Check if we've been asked for help. */
if (argc < 3 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0)
usage_exit (progname, 0) ;
/* Set all fields of the struct to zero bytes. */
memset (&info, 0, sizeof (info)) ;
/* Get the time in case we need it later. */
read_localtime (&timedata) ;
for (k = 1 ; k < argc ; k++)
{ if (argv [k][0] != '-')
{ if (filenames [0] == NULL)
filenames [0] = argv [k] ;
else if (filenames [1] == NULL)
filenames [1] = argv [k] ;
else
{ printf ("Error : Already have two file names on the command line and then found '%s'.\n\n", argv [k]) ;
usage_exit (progname, 1) ;
} ;
continue ;
} ;
#define HANDLE_BEXT_ARG(cmd, field) \
if (strcmp (argv [k], cmd) == 0) \
{ k ++ ; \
if (k == argc) missing_param (argv [k - 1]) ; \
info.field = argv [k] ; \
continue ; \
} ;
HANDLE_BEXT_ARG ("--bext-description", description) ;
HANDLE_BEXT_ARG ("--bext-originator", originator) ;
HANDLE_BEXT_ARG ("--bext-orig-ref", originator_reference) ;
HANDLE_BEXT_ARG ("--bext-umid", umid) ;
HANDLE_BEXT_ARG ("--bext-orig-date", origination_date) ;
HANDLE_BEXT_ARG ("--bext-orig-time", origination_time) ;
HANDLE_BEXT_ARG ("--bext-loudness-value", loudness_value) ;
HANDLE_BEXT_ARG ("--bext-loudness-range", loudness_range) ;
HANDLE_BEXT_ARG ("--bext-max-truepeak", max_true_peak_level) ;
HANDLE_BEXT_ARG ("--bext-max-momentary", max_momentary_loudness) ;
HANDLE_BEXT_ARG ("--bext-max-shortterm", max_shortterm_loudness) ;
HANDLE_BEXT_ARG ("--bext-coding-hist", coding_history) ;
HANDLE_BEXT_ARG ("--bext-time-ref", time_ref) ;
#define HANDLE_STR_ARG(cmd, field) \
if (strcmp (argv [k], cmd) == 0) \
{ k ++ ; \
if (k == argc) missing_param (argv [k - 1]) ; \
info.field = argv [k] ; \
continue ; \
} ;
HANDLE_STR_ARG ("--str-comment", comment) ;
HANDLE_STR_ARG ("--str-title", title) ;
HANDLE_STR_ARG ("--str-copyright", copyright) ;
HANDLE_STR_ARG ("--str-artist", artist) ;
HANDLE_STR_ARG ("--str-date", date) ;
HANDLE_STR_ARG ("--str-album", album) ;
HANDLE_STR_ARG ("--str-license", license) ;
/* Following options do not take an argument. */
if (strcmp (argv [k], "--bext-auto-time-date") == 0)
{ snprintf (time, sizeof (time), "%02d:%02d:%02d", timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ;
info.origination_time = time ;
snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ;
info.origination_date = date ;
continue ;
} ;
if (strcmp (argv [k], "--bext-auto-time") == 0)
{ snprintf (time, sizeof (time), "%02d:%02d:%02d", timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ;
info.origination_time = time ;
continue ;
} ;
if (strcmp (argv [k], "--bext-auto-date") == 0)
{ snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ;
info.origination_date = strdup (date) ;
continue ;
} ;
if (strcmp (argv [k], "--str-auto-date") == 0)
{ snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ;
info.date = strdup (date) ;
continue ;
} ;
printf ("Error : Don't know what to do with command line arg '%s'.\n\n", argv [k]) ;
usage_exit (progname, 1) ;
} ;
/* Find out if any of the 'bext' fields are set. */
info.has_bext_fields = has_bext_fields_set (&info) ;
if (filenames [0] == NULL)
{ printf ("Error : No input file specificed.\n\n") ;
exit (1) ;
} ;
if (filenames [1] != NULL && strcmp (filenames [0], filenames [1]) == 0)
{ printf ("Error : Input and output files are the same.\n\n") ;
exit (1) ;
} ;
if (info.coding_history != NULL && filenames [1] == NULL)
{ printf ("\n"
"Error : Trying to update coding history of an existing file which unfortunately\n"
" is not supported. Instead, create a new file using :\n"
"\n"
" %s --bext-coding-hist \"Coding history\" old_file.wav new_file.wav\n"
"\n",
progname) ;
exit (1) ;
} ;
sfe_apply_metadata_changes (filenames, &info) ;
return 0 ;
} /* main */
/*==============================================================================
** Print version and usage.
*/
static void
usage_exit (const char *progname, int exit_code)
{ printf ("\nUsage :\n\n"
" %s [options] <file>\n"
" %s [options] <input file> <output file>\n"
"\n",
progname, progname) ;
puts (
"Where an option is made up of a pair of a field to set (one of\n"
"the 'bext' or metadata fields below) and a string. Fields are\n"
"as follows :\n"
) ;
puts (
" --bext-description Set the 'bext' description.\n"
" --bext-originator Set the 'bext' originator.\n"
" --bext-orig-ref Set the 'bext' originator reference.\n"
" --bext-umid Set the 'bext' UMID.\n"
" --bext-orig-date Set the 'bext' origination date.\n"
" --bext-orig-time Set the 'bext' origination time.\n"
" --bext-loudness-value Set the 'bext' loudness value.\n"
" --bext-loudness-range Set the 'bext' loudness range.\n"
" --bext-max-truepeak Set the 'bext' max. true peak level\n"
" --bext-max-momentary Set the 'bext' max. momentary loudness\n"
" --bext-max-shortterm Set the 'bext' max. short term loudness\n"
" --bext-coding-hist Set the 'bext' coding history.\n"
" --bext-time-ref Set the 'bext' Time ref.\n"
"\n"
" --str-comment Set the metadata comment.\n"
" --str-title Set the metadata title.\n"
" --str-copyright Set the metadata copyright.\n"
" --str-artist Set the metadata artist.\n"
" --str-date Set the metadata date.\n"
" --str-album Set the metadata album.\n"
" --str-license Set the metadata license.\n"
) ;
puts (
"There are also the following arguments which do not take a\n"
"parameter :\n\n"
" --bext-auto-time-date Set the 'bext' time and date to current time/date.\n"
" --bext-auto-time Set the 'bext' time to current time.\n"
" --bext-auto-date Set the 'bext' date to current date.\n"
" --str-auto-date Set the metadata date to current date.\n"
) ;
puts (
"Most of the above operations can be done in-place on an existing\n"
"file. If any operation cannot be performed, the application will\n"
"exit with an appropriate error message.\n"
) ;
printf ("Using %s.\n\n", sf_version_string ()) ;
exit (exit_code) ;
} /* usage_exit */
static void
missing_param (const char * option)
{
printf ("Error : Option '%s' needs a parameter but doesn't seem to have one.\n\n", option) ;
exit (1) ;
} /* missing_param */
/*==============================================================================
*/
static int
has_bext_fields_set (const METADATA_INFO * info)
{
if (info->description || info->originator || info->originator_reference)
return 1 ;
if (info->origination_date || info->origination_time || info->umid || info->coding_history || info->time_ref)
return 1 ;
if (info->loudness_value || info->loudness_range || info->max_true_peak_level || info->max_momentary_loudness || info->max_shortterm_loudness)
return 1 ;
return 0 ;
} /* has_bext_fields_set */
static void
read_localtime (struct tm * timedata)
{ time_t current ;
time (&current) ;
memset (timedata, 0, sizeof (struct tm)) ;
#if defined (_WIN32)
/* If the re-entrant version is available, use it. */
localtime_s (timedata, &current) ;
#elif defined (HAVE_LOCALTIME_R)
/* If the re-entrant version is available, use it. */
localtime_r (&current, timedata) ;
#elif defined (HAVE_LOCALTIME)
{
struct tm *tmptr ;
/* Otherwise use the standard one and copy the data to local storage. */
if ((tmptr = localtime (&current)) != NULL)
memcpy (timedata, tmptr, sizeof (struct tm)) ;
}
#endif
return ;
} /* read_localtime */

View file

@ -0,0 +1,860 @@
/*
** Copyright (C) 1999-2018 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#else
#include "sf_unistd.h"
#endif
#include <sndfile.h>
#include "common.h"
#if HAVE_ALSA_ASOUNDLIB_H
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#include <alsa/asoundlib.h>
#include <sys/time.h>
#endif
#if defined (__ANDROID__)
#elif defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__)
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#elif HAVE_SNDIO_H
#include <sndio.h>
#elif (defined (sun) && defined (unix)) || defined(__NetBSD__)
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
#elif (OS_IS_WIN32 == 1)
#include <windows.h>
#include <mmsystem.h>
#endif
#define SIGNED_SIZEOF(x) ((int) sizeof (x))
#define BUFFER_LEN (2048)
/*------------------------------------------------------------------------------
** Linux/OSS functions for playing a sound.
*/
#if HAVE_ALSA_ASOUNDLIB_H
static snd_pcm_t * alsa_open (int channels, unsigned srate, int realtime) ;
static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ;
static void
alsa_play (int argc, char *argv [])
{ static float buffer [BUFFER_LEN] ;
SNDFILE *sndfile ;
SF_INFO sfinfo ;
snd_pcm_t * alsa_dev ;
int k, readcount, subformat ;
for (k = 1 ; k < argc ; k++)
{ memset (&sfinfo, 0, sizeof (sfinfo)) ;
printf ("Playing %s\n", argv [k]) ;
if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
{ puts (sf_strerror (NULL)) ;
continue ;
} ;
if (sfinfo.channels < 1 || sfinfo.channels > 2)
{ printf ("Error : channels = %d.\n", sfinfo.channels) ;
continue ;
} ;
if ((alsa_dev = alsa_open (sfinfo.channels, (unsigned) sfinfo.samplerate, SF_FALSE)) == NULL)
continue ;
subformat = sfinfo.format & SF_FORMAT_SUBMASK ;
if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)
{ double scale ;
int m ;
sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;
if (scale > 1.0)
scale = 1.0 / scale ;
else
scale = 1.0 ;
while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))
{ for (m = 0 ; m < readcount ; m++)
buffer [m] *= scale ;
alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;
} ;
}
else
{ while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN)))
alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ;
} ;
snd_pcm_drain (alsa_dev) ;
snd_pcm_close (alsa_dev) ;
sf_close (sndfile) ;
} ;
return ;
} /* alsa_play */
static snd_pcm_t *
alsa_open (int channels, unsigned samplerate, int realtime)
{ const char * device = "default" ;
snd_pcm_t *alsa_dev = NULL ;
snd_pcm_hw_params_t *hw_params ;
snd_pcm_uframes_t buffer_size ;
snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
snd_pcm_sw_params_t *sw_params ;
int err ;
if (realtime)
{ alsa_period_size = 256 ;
alsa_buffer_frames = 3 * alsa_period_size ;
}
else
{ alsa_period_size = 1024 ;
alsa_buffer_frames = 4 * alsa_period_size ;
} ;
if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{ fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
goto catch_error ;
} ;
snd_pcm_nonblock (alsa_dev, 0) ;
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{ fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0)
{ fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{ fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
{ fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0)
{ fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0)
{ fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
{ fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
{ fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0)
{ fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
/* extra check: if we have only one period, this code won't work */
snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
if (alsa_period_size == buffer_size)
{ fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
goto catch_error ;
} ;
snd_pcm_hw_params_free (hw_params) ;
if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
{ fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0)
{ fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
goto catch_error ;
} ;
/* note: set start threshold to delay start until the ring buffer is full */
snd_pcm_sw_params_current (alsa_dev, sw_params) ;
if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0)
{ fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
goto catch_error ;
} ;
if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0)
{ fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
goto catch_error ;
} ;
snd_pcm_sw_params_free (sw_params) ;
snd_pcm_reset (alsa_dev) ;
catch_error :
if (err < 0 && alsa_dev != NULL)
{ snd_pcm_close (alsa_dev) ;
return NULL ;
} ;
return alsa_dev ;
} /* alsa_open */
static int
alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels)
{ static int epipe_count = 0 ;
int total = 0 ;
int retval ;
if (epipe_count > 0)
epipe_count -- ;
while (total < frames)
{ retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ;
if (retval >= 0)
{ total += retval ;
if (total == frames)
return total ;
continue ;
} ;
switch (retval)
{ case -EAGAIN :
puts ("alsa_write_float: EAGAIN") ;
continue ;
break ;
case -EPIPE :
if (epipe_count > 0)
{ printf ("alsa_write_float: EPIPE %d\n", epipe_count) ;
if (epipe_count > 140)
return retval ;
} ;
epipe_count += 100 ;
#if 0
if (0)
{ snd_pcm_status_t *status ;
snd_pcm_status_alloca (&status) ;
if ((retval = snd_pcm_status (alsa_dev, status)) < 0)
fprintf (stderr, "alsa_out: xrun. can't determine length\n") ;
else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN)
{ struct timeval now, diff, tstamp ;
gettimeofday (&now, 0) ;
snd_pcm_status_get_trigger_tstamp (status, &tstamp) ;
timersub (&now, &tstamp, &diff) ;
fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n",
diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ;
}
else
fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ;
} ;
#endif
snd_pcm_prepare (alsa_dev) ;
break ;
case -EBADFD :
fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;
return 0 ;
break ;
#if defined ESTRPIPE && ESTRPIPE != EPIPE
case -ESTRPIPE :
fprintf (stderr, "alsa_write_float: Suspend event.n") ;
return 0 ;
break ;
#endif
case -EIO :
puts ("alsa_write_float: EIO") ;
return 0 ;
default :
fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ;
return 0 ;
break ;
} ; /* switch */
} ; /* while */
return total ;
} /* alsa_write_float */
#endif /* HAVE_ALSA_ASOUNDLIB_H */
/*------------------------------------------------------------------------------
** Linux/OSS functions for playing a sound.
*/
#if !defined (__ANDROID__) && (defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__))
static int opensoundsys_open_device (int channels, int srate) ;
static int
opensoundsys_play (int argc, char *argv [])
{ static short buffer [BUFFER_LEN] ;
SNDFILE *sndfile ;
SF_INFO sfinfo ;
int k, audio_device, readcount, writecount, subformat ;
for (k = 1 ; k < argc ; k++)
{ memset (&sfinfo, 0, sizeof (sfinfo)) ;
printf ("Playing %s\n", argv [k]) ;
if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
{ puts (sf_strerror (NULL)) ;
continue ;
} ;
if (sfinfo.channels < 1 || sfinfo.channels > 2)
{ printf ("Error : channels = %d.\n", sfinfo.channels) ;
continue ;
} ;
audio_device = opensoundsys_open_device (sfinfo.channels, sfinfo.samplerate) ;
subformat = sfinfo.format & SF_FORMAT_SUBMASK ;
if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)
{ static float float_buffer [BUFFER_LEN] ;
double scale ;
int m ;
sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;
if (scale < 1e-10)
scale = 1.0 ;
else
scale = 32700.0 / scale ;
while ((readcount = sf_read_float (sndfile, float_buffer, BUFFER_LEN)))
{ for (m = 0 ; m < readcount ; m++)
buffer [m] = scale * float_buffer [m] ;
writecount = write (audio_device, buffer, readcount * sizeof (short)) ;
} ;
}
else
{ while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN)))
writecount = write (audio_device, buffer, readcount * sizeof (short)) ;
} ;
if (ioctl (audio_device, SNDCTL_DSP_POST, 0) == -1)
perror ("ioctl (SNDCTL_DSP_POST) ") ;
if (ioctl (audio_device, SNDCTL_DSP_SYNC, 0) == -1)
perror ("ioctl (SNDCTL_DSP_SYNC) ") ;
close (audio_device) ;
sf_close (sndfile) ;
} ;
return writecount ;
} /* opensoundsys_play */
static int
opensoundsys_open_device (int channels, int srate)
{ int fd, stereo, fmt ;
if ((fd = open ("/dev/dsp", O_WRONLY, 0)) == -1 &&
(fd = open ("/dev/sound/dsp", O_WRONLY, 0)) == -1)
{ perror ("opensoundsys_open_device : open ") ;
exit (1) ;
} ;
stereo = 0 ;
if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1)
{ /* Fatal error */
perror ("opensoundsys_open_device : stereo ") ;
exit (1) ;
} ;
if (ioctl (fd, SNDCTL_DSP_RESET, 0))
{ perror ("opensoundsys_open_device : reset ") ;
exit (1) ;
} ;
fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) != 0)
{ perror ("opensoundsys_open_device : set format ") ;
exit (1) ;
} ;
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) != 0)
{ perror ("opensoundsys_open_device : channels ") ;
exit (1) ;
} ;
if (ioctl (fd, SNDCTL_DSP_SPEED, &srate) != 0)
{ perror ("opensoundsys_open_device : sample rate ") ;
exit (1) ;
} ;
if (ioctl (fd, SNDCTL_DSP_SYNC, 0) != 0)
{ perror ("opensoundsys_open_device : sync ") ;
exit (1) ;
} ;
return fd ;
} /* opensoundsys_open_device */
#endif /* __linux__ */
/*------------------------------------------------------------------------------
** Mac OS X functions for playing a sound.
*/
/* MacOSX 10.8 use a new Audio API. Someone needs to write some code for it. */
/*------------------------------------------------------------------------------
** Win32 functions for playing a sound.
**
** This API sucks. Its needlessly complicated and is *WAY* too loose with
** passing pointers around in integers and using char* pointers to
** point to data instead of short*. It plain sucks!
*/
#if (OS_IS_WIN32 == 1)
#define WIN32_BUFFER_LEN (1 << 15)
typedef struct
{ HWAVEOUT hwave ;
WAVEHDR whdr [2] ;
CRITICAL_SECTION mutex ; /* to control access to BuffersInUSe */
HANDLE Event ; /* signal that a buffer is free */
short buffer [WIN32_BUFFER_LEN / sizeof (short)] ;
int current, bufferlen ;
int BuffersInUse ;
SNDFILE *sndfile ;
SF_INFO sfinfo ;
sf_count_t remaining ;
} Win32_Audio_Data ;
static void
win32_play_data (Win32_Audio_Data *audio_data)
{ int thisread, readcount ;
/* fill a buffer if there is more data and we can read it sucessfully */
readcount = (audio_data->remaining > audio_data->bufferlen) ? audio_data->bufferlen : (int) audio_data->remaining ;
short *lpData = (short *) (void *) audio_data->whdr [audio_data->current].lpData ;
thisread = (int) sf_read_short (audio_data->sndfile, lpData, readcount) ;
audio_data->remaining -= thisread ;
if (thisread > 0)
{ /* Fix buffer length if this is only a partial block. */
if (thisread < audio_data->bufferlen)
audio_data->whdr [audio_data->current].dwBufferLength = thisread * sizeof (short) ;
/* Queue the WAVEHDR */
waveOutWrite (audio_data->hwave, (LPWAVEHDR) &(audio_data->whdr [audio_data->current]), sizeof (WAVEHDR)) ;
/* count another buffer in use */
EnterCriticalSection (&audio_data->mutex) ;
audio_data->BuffersInUse ++ ;
LeaveCriticalSection (&audio_data->mutex) ;
/* use the other buffer next time */
audio_data->current = (audio_data->current + 1) % 2 ;
} ;
return ;
} /* win32_play_data */
static void CALLBACK
win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD_PTR data, DWORD param1, DWORD param2)
{ Win32_Audio_Data *audio_data ;
/* Prevent compiler warnings. */
(void) hwave ;
(void) param1 ;
(void) param2 ;
if (data == 0)
return ;
/*
** I consider this technique of passing a pointer via an integer as
** fundamentally broken but thats the way microsoft has defined the
** interface.
*/
audio_data = (Win32_Audio_Data*) data ;
/* let main loop know a buffer is free */
if (msg == MM_WOM_DONE)
{ EnterCriticalSection (&audio_data->mutex) ;
audio_data->BuffersInUse -- ;
LeaveCriticalSection (&audio_data->mutex) ;
SetEvent (audio_data->Event) ;
} ;
return ;
} /* win32_audio_out_callback */
static void
win32_play (int argc, char *argv [])
{ Win32_Audio_Data audio_data ;
WAVEFORMATEX wf ;
int k, error ;
audio_data.sndfile = NULL ;
audio_data.hwave = 0 ;
for (k = 1 ; k < argc ; k++)
{ printf ("Playing %s\n", argv [k]) ;
if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo))))
{ puts (sf_strerror (NULL)) ;
continue ;
} ;
audio_data.remaining = audio_data.sfinfo.frames * audio_data.sfinfo.channels ;
audio_data.current = 0 ;
InitializeCriticalSection (&audio_data.mutex) ;
audio_data.Event = CreateEvent (0, FALSE, FALSE, 0) ;
wf.nChannels = audio_data.sfinfo.channels ;
wf.wFormatTag = WAVE_FORMAT_PCM ;
wf.cbSize = 0 ;
wf.wBitsPerSample = 16 ;
wf.nSamplesPerSec = audio_data.sfinfo.samplerate ;
wf.nBlockAlign = audio_data.sfinfo.channels * sizeof (short) ;
wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ;
error = waveOutOpen (&(audio_data.hwave), WAVE_MAPPER, &wf, (DWORD_PTR) win32_audio_out_callback,
(DWORD_PTR) &audio_data, CALLBACK_FUNCTION) ;
if (error)
{ puts ("waveOutOpen failed.") ;
audio_data.hwave = 0 ;
continue ;
} ;
audio_data.whdr [0].lpData = (char*) audio_data.buffer ;
audio_data.whdr [1].lpData = ((char*) audio_data.buffer) + sizeof (audio_data.buffer) / 2 ;
audio_data.whdr [0].dwBufferLength = sizeof (audio_data.buffer) / 2 ;
audio_data.whdr [1].dwBufferLength = sizeof (audio_data.buffer) / 2 ;
audio_data.whdr [0].dwFlags = 0 ;
audio_data.whdr [1].dwFlags = 0 ;
/* length of each audio buffer in samples */
audio_data.bufferlen = sizeof (audio_data.buffer) / 2 / sizeof (short) ;
/* Prepare the WAVEHDRs */
if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR))))
{ printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ;
waveOutClose (audio_data.hwave) ;
continue ;
} ;
if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR))))
{ printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ;
waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ;
waveOutClose (audio_data.hwave) ;
continue ;
} ;
/* Fill up both buffers with audio data */
audio_data.BuffersInUse = 0 ;
win32_play_data (&audio_data) ;
win32_play_data (&audio_data) ;
/* loop until both buffers are released */
while (audio_data.BuffersInUse > 0)
{
/* wait for buffer to be released */
WaitForSingleObject (audio_data.Event, INFINITE) ;
/* refill the buffer if there is more data to play */
win32_play_data (&audio_data) ;
} ;
waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ;
waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)) ;
waveOutClose (audio_data.hwave) ;
audio_data.hwave = 0 ;
DeleteCriticalSection (&audio_data.mutex) ;
sf_close (audio_data.sndfile) ;
} ;
} /* win32_play */
#endif /* Win32 */
/*------------------------------------------------------------------------------
** OpenBSD's sndio.
*/
#if HAVE_SNDIO_H
static void
sndio_play (int argc, char *argv [])
{ struct sio_hdl *hdl ;
struct sio_par par ;
short buffer [BUFFER_LEN] ;
SNDFILE *sndfile ;
SF_INFO sfinfo ;
int k, readcount ;
for (k = 1 ; k < argc ; k++)
{ printf ("Playing %s\n", argv [k]) ;
if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
{ puts (sf_strerror (NULL)) ;
continue ;
} ;
if (sfinfo.channels < 1 || sfinfo.channels > 2)
{ printf ("Error : channels = %d.\n", sfinfo.channels) ;
continue ;
} ;
if ((hdl = sio_open (NULL, SIO_PLAY, 0)) == NULL)
{ fprintf (stderr, "open sndio device failed") ;
return ;
} ;
sio_initpar (&par) ;
par.rate = sfinfo.samplerate ;
par.pchan = sfinfo.channels ;
par.bits = 16 ;
par.sig = 1 ;
par.le = SIO_LE_NATIVE ;
if (! sio_setpar (hdl, &par) || ! sio_getpar (hdl, &par))
{ fprintf (stderr, "set sndio params failed") ;
return ;
} ;
if (! sio_start (hdl))
{ fprintf (stderr, "sndio start failed") ;
return ;
} ;
while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN)))
sio_write (hdl, buffer, readcount * sizeof (short)) ;
sio_close (hdl) ;
} ;
return ;
} /* sndio_play */
#endif /* sndio */
/*------------------------------------------------------------------------------
** Solaris.
*/
#if (defined (sun) && defined (unix)) || defined(__NetBSD__)
static void
solaris_play (int argc, char *argv [])
{ static short buffer [BUFFER_LEN] ;
audio_info_t audio_info ;
SNDFILE *sndfile ;
SF_INFO sfinfo ;
unsigned long delay_time ;
long k, start_count, output_count, write_count, read_count ;
int audio_fd, error, done ;
for (k = 1 ; k < argc ; k++)
{ printf ("Playing %s\n", argv [k]) ;
if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo)))
{ puts (sf_strerror (NULL)) ;
continue ;
} ;
if (sfinfo.channels < 1 || sfinfo.channels > 2)
{ printf ("Error : channels = %d.\n", sfinfo.channels) ;
continue ;
} ;
/* open the audio device - write only, non-blocking */
if ((audio_fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0)
{ perror ("open (/dev/audio) failed") ;
return ;
} ;
/* Retrive standard values. */
AUDIO_INITINFO (&audio_info) ;
audio_info.play.sample_rate = sfinfo.samplerate ;
audio_info.play.channels = sfinfo.channels ;
audio_info.play.precision = 16 ;
audio_info.play.encoding = AUDIO_ENCODING_LINEAR ;
if ((error = ioctl (audio_fd, AUDIO_SETINFO, &audio_info)))
{ perror ("ioctl (AUDIO_SETINFO) failed") ;
return ;
} ;
/* Delay time equal to 1/4 of a buffer in microseconds. */
delay_time = (BUFFER_LEN * 1000000) / (audio_info.play.sample_rate * 4) ;
done = 0 ;
while (! done)
{ read_count = sf_read_short (sndfile, buffer, BUFFER_LEN) ;
if (read_count < BUFFER_LEN)
{ memset (&(buffer [read_count]), 0, (BUFFER_LEN - read_count) * sizeof (short)) ;
/* Tell the main application to terminate. */
done = SF_TRUE ;
} ;
start_count = 0 ;
output_count = BUFFER_LEN * sizeof (short) ;
while (output_count > 0)
{ /* write as much data as possible */
write_count = write (audio_fd, &(buffer [start_count]), output_count) ;
if (write_count > 0)
{ output_count -= write_count ;
start_count += write_count ;
}
else
{ /* Give the audio output time to catch up. */
usleep (delay_time) ;
} ;
} ; /* while (outpur_count > 0) */
} ; /* while (! done) */
close (audio_fd) ;
} ;
return ;
} /* solaris_play */
#endif /* Solaris or NetBSD */
/*==============================================================================
** Main function.
*/
int
main (int argc, char *argv [])
{
if (argc < 2)
{
printf ("\nUsage : %s <input sound file>\n\n", program_name (argv [0])) ;
printf ("Using %s.\n\n", sf_version_string ()) ;
#if (OS_IS_WIN32 == 1)
printf ("This is a Unix style command line application which\n"
"should be run in a MSDOS box or Command Shell window.\n\n") ;
printf ("Sleeping for 5 seconds before exiting.\n\n") ;
Sleep (5 * 1000) ;
#endif
return 1 ;
} ;
#if defined (__ANDROID__)
puts ("*** Playing sound not yet supported on Android.") ;
puts ("*** Please feel free to submit a patch.") ;
return 1 ;
#elif defined (__linux__)
#if HAVE_ALSA_ASOUNDLIB_H
if (access ("/proc/asound/cards", R_OK) == 0)
alsa_play (argc, argv) ;
else
#endif
opensoundsys_play (argc, argv) ;
#elif defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__)
opensoundsys_play (argc, argv) ;
#elif HAVE_SNDIO_H
sndio_play (argc, argv) ;
#elif (defined (sun) && defined (unix)) || defined(__NetBSD__)
solaris_play (argc, argv) ;
#elif (OS_IS_WIN32 == 1)
win32_play (argc, argv) ;
#else
puts ("*** Playing sound not supported on this platform.") ;
puts ("*** Please feel free to submit a patch.") ;
return 1 ;
#endif
return 0 ;
} /* main */

View file

@ -0,0 +1,302 @@
/*
** Copyright (C) 2010-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the author nor the names of any contributors may be used
** to endorse or promote products derived from this software without
** specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sfconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#else
#include "sf_unistd.h"
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sndfile.h>
#include "common.h"
#define BUFFER_LEN (1 << 16)
#define NOT(x) (! (x))
#ifndef _WIN32
typedef off_t sf_off_t ;
#else
typedef long long sf_off_t ;
#endif
static void usage_exit (const char *progname) ;
static void salvage_file (const char * broken_wav, const char * fixed_w64) ;
int
main (int argc, char *argv [])
{
if (argc != 3)
usage_exit (program_name (argv [0])) ;
salvage_file (argv [1], argv [2]) ;
return 0 ;
} /* main */
/*==============================================================================
*/
static void lseek_or_die (int fd, sf_off_t offset, int whence) ;
static sf_off_t get_file_length (int fd, const char * name) ;
static sf_count_t find_data_offset (int fd, int format) ;
static void copy_data (int fd, SNDFILE * sndfile, int readsize) ;
static void
usage_exit (const char *progname)
{ printf ("Usage :\n\n %s <broken wav file> <fixed w64 file>\n\n", progname) ;
puts ("Salvages the audio data from WAV files which are more than 4G in length.\n") ;
printf ("Using %s.\n\n", sf_version_string ()) ;
exit (1) ;
} /* usage_exit */
static void
salvage_file (const char * broken_wav, const char * fixed_w64)
{ SNDFILE * sndfile ;
SF_INFO sfinfo ;
sf_count_t broken_len, data_offset ;
int fd, read_size ;
if (strcmp (broken_wav, fixed_w64) == 0)
{ printf ("Error : Input and output files must be different.\n\n") ;
exit (1) ;
} ;
if ((fd = open (broken_wav, O_RDONLY)) < 0)
{ printf ("Error : Not able to open file '%s' : %s\n", broken_wav, strerror (errno)) ;
exit (1) ;
} ;
broken_len = get_file_length (fd, broken_wav) ;
if (broken_len <= 0xffffffff)
printf ("File is not greater than 4Gig but salvaging anyway.\n") ;
/* Grab the format info from the broken file. */
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((sndfile = sf_open (broken_wav, SFM_READ, &sfinfo)) == NULL)
{ printf ("sf_open ('%s') failed : %s\n", broken_wav, sf_strerror (NULL)) ;
exit (1) ;
} ;
sf_close (sndfile) ;
data_offset = find_data_offset (fd, sfinfo.format & SF_FORMAT_TYPEMASK) ;
printf ("Offset to audio data : %" PRId64 "\n", data_offset) ;
switch (sfinfo.format & SF_FORMAT_TYPEMASK)
{ case SF_FORMAT_WAV :
case SF_FORMAT_WAVEX :
sfinfo.format = SF_FORMAT_W64 | (sfinfo.format & SF_FORMAT_SUBMASK) ;
break ;
default :
printf ("Don't currently support this file type.\n") ;
exit (1) ;
} ;
switch (sfinfo.format & SF_FORMAT_SUBMASK)
{ case SF_FORMAT_PCM_U8 :
case SF_FORMAT_PCM_S8 :
read_size = 1 ;
break ;
case SF_FORMAT_PCM_16 :
read_size = 2 ;
break ;
case SF_FORMAT_PCM_24 :
read_size = 3 ;
break ;
case SF_FORMAT_PCM_32 :
case SF_FORMAT_FLOAT :
read_size = 4 ;
break ;
case SF_FORMAT_DOUBLE :
read_size = 8 ;
break ;
default :
printf ("Sorry, don't currently support this file encoding type.\n") ;
exit (1) ;
} ;
read_size *= sfinfo.channels ;
if ((sndfile = sf_open (fixed_w64, SFM_WRITE, &sfinfo)) == NULL)
{ printf ("sf_open ('%s') failed : %s\n", fixed_w64, sf_strerror (NULL)) ;
exit (1) ;
} ;
lseek_or_die (fd, data_offset, SEEK_SET) ;
copy_data (fd, sndfile, read_size) ;
sf_close (sndfile) ;
puts ("Done!") ;
} /* salvage_file */
/*------------------------------------------------------------------------------
*/
static void
lseek_or_die (int fd, sf_off_t offset, int whence)
{
#ifndef _WIN32
if (lseek (fd, offset, whence) < 0)
#else
if (_lseeki64 (fd, offset, whence) < 0)
#endif
{ printf ("lseek failed : %s\n", strerror (errno)) ;
exit (1) ;
} ;
return ;
} /* lseek_or_die */
static sf_off_t
get_file_length (int fd, const char * name)
{
#ifndef _WIN32
struct stat sbuf ;
#else
struct _stat64 sbuf ;
#endif
if (sizeof (sbuf.st_size) != 8)
{ puts ("Error : sizeof (sbuf.st_size) != 8. Was program compiled with\n"
" 64 bit file offsets?\n") ;
exit (1) ;
} ;
#ifndef _WIN32
if (fstat (fd, &sbuf) != 0)
#else
if (_fstat64 (fd, &sbuf) != 0)
#endif
{ printf ("Error : fstat ('%s') failed : %s\n", name, strerror (errno)) ;
exit (1) ;
} ;
return sbuf.st_size ;
} /* get_file_length */
static sf_count_t
find_data_offset (int fd, int format)
{ char buffer [8192], *cptr ;
const char * target = "XXXX" ;
sf_count_t offset = -1, extra ;
int rlen, slen ;
switch (format)
{ case SF_FORMAT_WAV :
case SF_FORMAT_WAVEX :
target = "data" ;
extra = 8 ;
break ;
case SF_FORMAT_AIFF :
target = "SSND" ;
extra = 16 ;
break ;
default :
puts ("Error : Sorry, don't handle this input file format.\n") ;
exit (1) ;
} ;
slen = (int) strlen (target) ;
lseek_or_die (fd, 0, SEEK_SET) ;
printf ("Searching for '%s' maker.\n", target) ;
if ((rlen = read (fd, buffer, sizeof (buffer))) < 0)
{ printf ("Error : failed read : %s\n", strerror (errno)) ;
exit (1) ;
} ;
cptr = memchr (buffer, target [0], rlen - slen) ;
if (cptr && memcmp (cptr, target, slen) == 0)
offset = cptr - buffer ;
else
{ printf ("Error : Could not find data offset.\n") ;
exit (1) ;
} ;
return offset + extra ;
} /* find_data_offset */
static void
copy_data (int fd, SNDFILE * sndfile, int readsize)
{ static char * buffer ;
sf_count_t readlen, count ;
int bufferlen, done = 0 ;
bufferlen = readsize * 1024 ;
buffer = malloc (bufferlen) ;
while (NOT (done) && (readlen = read (fd, buffer, bufferlen)) >= 0)
{ if (readlen < bufferlen)
{ readlen -= readlen % readsize ;
done = 1 ;
} ;
if ((count = sf_write_raw (sndfile, buffer, readlen)) != readlen)
{ printf ("Error : sf_write_raw returned %" PRId64 " : %s\n", count, sf_strerror (sndfile)) ;
return ;
} ;
} ;
free (buffer) ;
return ;
} /* copy_data */

View file

@ -0,0 +1,198 @@
#!/usr/bin/env python
# Copyright (C) 2008-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the author nor the names of any contributors may be used
# to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Simple test script for the sndfile-metadata-set program.
from __future__ import print_function
try:
# py2
import commands
except ImportError:
# py3
import subprocess as commands
import os, sys
import time, datetime
class Programs:
def __init__ (self, needs_exe):
if needs_exe:
extension = ".exe"
else:
extension = ""
self.meta_set_prog = "./sndfile-metadata-set" + extension
self.meta_get_prog = "./sndfile-metadata-get" + extension
self.make_sine_prog = "../examples/make_sine" + extension
def _run_command (self, should_fail, cmd):
status, output = commands.getstatusoutput (cmd)
if should_fail and not status:
print("\n\nError : command '%s' should have failed." % cmd)
print(output)
print()
sys.exit (1)
if not should_fail and status:
print("\n\nError : command '%s' should not have failed." % cmd)
print(output)
print()
sys.exit (1)
return output
def meta_set (self, should_fail, args):
return self._run_command (should_fail, self.meta_set_prog + " " + args)
def meta_get (self, should_fail, args):
return self._run_command (should_fail, self.meta_get_prog + " " + args)
def make_sine (self):
return os.system (self.make_sine_prog)
def check_executables (self):
for name in [ self.meta_set_prog, self.meta_get_prog, self.make_sine_prog ]:
if not (os.path.isfile (name)):
print("\n\nError : Can't find executable '%s'. Have you run make?" % name)
sys.exit (1)
def print_test_name (name):
print(" %-30s :" % name, end="")
def assert_info (programs, filename, arg, value):
output = programs.meta_get (False, "%s %s" % (arg, filename))
if output.find (value) < 0:
print("\n\nError : not able to find '%s'." % value)
print(output)
sys.exit (1)
return
def test_empty_fail (programs):
print_test_name ("Empty fail test")
output = programs.meta_set (True, "--bext-description Alpha sine.wav")
print("ok")
def test_copy (programs):
print_test_name ("Copy test")
output = programs.meta_set (False, "--bext-description \"First Try\" sine.wav output.wav")
assert_info (programs, "output.wav", "--bext-description", "First Try")
print("ok")
def test_update (programs, tests):
print_test_name ("Update test")
for arg, value in tests:
output = programs.meta_set (False, "%s \"%s\" output.wav" % (arg, value))
assert_info (programs, "output.wav", arg, value)
print("ok")
def test_post_mod (programs, tests):
print_test_name ("Post mod test")
for arg, value in tests:
assert_info (programs, "output.wav", arg, value)
print("ok")
def test_auto_date (programs):
print_test_name ("Auto date test")
output = programs.meta_set (False, "--bext-auto-time-date sine.wav date-time.wav")
target = datetime.date.today ().__str__ ()
assert_info (programs, "date-time.wav", "--bext-orig-date", target)
print("ok")
#-------------------------------------------------------------------------------
def test_coding_history (programs):
print_test_name ("Coding history test")
output = programs.meta_set (False, "--bext-coding-hist \"alpha beta\" output.wav")
output = programs.meta_get (False, "--bext-coding-hist output.wav")
print("ok")
#-------------------------------------------------------------------------------
def test_rewrite (programs):
print_test_name ("Rewrite test")
output = programs.meta_set (False, "--bext-originator \"Really, really long string\" output.wav")
output = programs.meta_set (False, "--bext-originator \"Short\" output.wav")
output = programs.meta_get (False, "--bext-originator output.wav")
if output.find ("really long") > 0:
print("\n\nError : output '%s' should not contain 'really long'." % output)
sys.exit (1)
print("ok")
#===============================================================================
test_dir = "programs"
print("\nTesting WAV metadata manipulation:")
if os.path.isdir (test_dir):
os.chdir (test_dir)
if len (sys.argv) >= 1 and sys.argv [1].endswith ("mingw32"):
needs_exe = True
else:
needs_exe = False
programs = Programs (needs_exe)
programs.check_executables ()
programs.make_sine ()
if not os.path.isfile ("sine.wav"):
print("\n\nError : Can't file file 'sine.wav'.")
sys.exit (1)
test_empty_fail (programs)
test_copy (programs)
tests = [
("--bext-description", "Alpha"), ("--bext-originator", "Beta"), ("--bext-orig-ref", "Charlie"),
("--bext-umid", "Delta"), ("--bext-orig-date", "2001-10-01"), ("--bext-orig-time", "01:02:03"),
("--str-title", "Echo"), ("--str-artist", "Fox trot")
]
test_auto_date (programs)
test_update (programs, tests)
test_post_mod (programs, tests)
test_update (programs, [ ("--str-artist", "Fox") ])
# This never worked.
# test_coding_history ()
test_rewrite (programs)
print()
sys.exit (0)