mirror of https://github.com/asterisk/asterisk
Add stereoize (bug #3142), faster than soxmix
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4859 65c4cc65-6c06-0410-ace0-fbb531ad65f31.2-netsec
parent
9fc931366e
commit
2184f91230
@ -1,3 +1,4 @@
|
|||||||
.depend
|
.depend
|
||||||
astman
|
astman
|
||||||
smsq
|
smsq
|
||||||
|
stereoize
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,300 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Programs for processing sound files in raw- or WAV-format.
|
||||||
|
* -- Useful functions for parsing command line options and
|
||||||
|
* issuing errors, warnings, and chit chat.
|
||||||
|
*
|
||||||
|
* Name: frame.h
|
||||||
|
* Version: see frame.c
|
||||||
|
* Author: Mark Roberts <mark@manumark.de>
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/****************************************************************************
|
||||||
|
* These are useful functions that all DSP programs might find handy
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* fileswitch for parseargs:
|
||||||
|
|
||||||
|
The following are masks for several different ways of opening files.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
Bit 0: Open infile?
|
||||||
|
Bit 1: Open infile as binary (as opposed to text)
|
||||||
|
Bit 2: Open outfile?
|
||||||
|
Bit 3: Open outfile as binary (as opposed to text)
|
||||||
|
Bit 4: Do not complain about too many file arguments
|
||||||
|
Bit 5: Open one file for input AND output, binary.
|
||||||
|
*/
|
||||||
|
#define INTEXT (1+0)
|
||||||
|
#define INBIN (1+2)
|
||||||
|
#define OUTTEXT (4)
|
||||||
|
#define OUTBIN (4+8)
|
||||||
|
#define NOFILES (0)
|
||||||
|
#define NOCOMPLAIN (16)
|
||||||
|
#define IOBIN (32)
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE (0==1)
|
||||||
|
#define TRUE (0==0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern unsigned int samplefrequency;
|
||||||
|
extern unsigned short samplewidth;
|
||||||
|
extern unsigned short channels;
|
||||||
|
extern int wavout; /* TRUE iff out file is .WAV file */
|
||||||
|
extern int iswav; /* TRUE iff in file was found to be a .WAV file */
|
||||||
|
extern FILE *in, *out;
|
||||||
|
extern char *infilename, *outfilename;
|
||||||
|
extern int verboselevel;
|
||||||
|
extern char *version; /* String to be issued as version string. Should
|
||||||
|
be set by application. */
|
||||||
|
extern char *usage; /* String to be issued as usage string. Should be
|
||||||
|
set by application. */
|
||||||
|
|
||||||
|
#define DEFAULTFREQ 44100
|
||||||
|
#define BUFFSIZE 50000 /* How many samples to read in one go (preferred) */
|
||||||
|
#define MINBUFFSIZE 5000 /* How many samples to read in one go (minimum) */
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
* Types of errors handled by argerrornum() *
|
||||||
|
*************************************************/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ME_NOINT,
|
||||||
|
ME_NODOUBLE,
|
||||||
|
ME_NOTIME,
|
||||||
|
ME_NOVOL,
|
||||||
|
ME_NOSWITCH,
|
||||||
|
ME_TOOMANYFILES,
|
||||||
|
ME_HEADERONTEXTFILE,
|
||||||
|
ME_NOINFILE,
|
||||||
|
ME_NOOUTFILE,
|
||||||
|
ME_NOIOFILE,
|
||||||
|
ME_NOSTDIN,
|
||||||
|
ME_NOSTDOUT,
|
||||||
|
ME_NOSTDIO,
|
||||||
|
ME_NOTENOUGHFILES,
|
||||||
|
ME_THISCANTHAPPEN
|
||||||
|
} Errornum;
|
||||||
|
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Create memory and copy 'string', returning a pointer to the copy.
|
||||||
|
NULL is returned if malloc fails.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern char *malloccopy( char *string);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Start the stopwatch and make sure the user is informed at end of program.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern void startstopwatch(void);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Writes the number of samples to result that are yet to be read from anyin.
|
||||||
|
I.e. the number of remaining bytes is divided by the number of bytes per
|
||||||
|
sample value, but not by the number of channels.
|
||||||
|
Return values are TRUE on success, FALSE on failure.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern int getremainingfilelength( FILE *anyin, long *result);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Read a .pk-header from 'anyin' and printf the entries.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
void readpkheader( FILE *anyin);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Read a .WAV header from 'anyin'.
|
||||||
|
If it is recognised, the data is used.
|
||||||
|
Otherwise, we assume it's PCM-data and ignore the header.
|
||||||
|
The global variable 'iswav' is set on success, otherwise cleared.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern void readwavheader( FILE *anyin);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Write a .WAV header to 'out'.
|
||||||
|
The filepointer is placed at the end of 'out' before operation.
|
||||||
|
This should be called before any data is
|
||||||
|
written, and again, when ALL the data has been written.
|
||||||
|
First time, this positions the file pointer correctly; second time, the
|
||||||
|
missing data can be inserted that wasn't known the first time round.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern void makewavheader( void);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Tests the character 'coal' for being a command line option character,
|
||||||
|
momentarrily '/' or '-'.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int isoptionchar (char coal);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for an option starting
|
||||||
|
with 'string'. The rest of the option is read as a time and passed
|
||||||
|
to *result, where the result is meant to mean 'number of samples' in
|
||||||
|
that time.
|
||||||
|
On failure, *result is unchanged.
|
||||||
|
return value is TRUE on success, FALSE otherwise.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
extern int parsetimearg( int argcount, char *args[], char *string,
|
||||||
|
int *result);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
The string argument is read as a time and passed to *result, where
|
||||||
|
the result is meant to mean 'number of samples' in that time. On
|
||||||
|
failure, *result is unchanged.
|
||||||
|
return value is TRUE on success, FALSE otherwise.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
int parsetime(char *string, int *result);
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
The string argument is read as a frequency and passed
|
||||||
|
to *result, where the result is meant to mean 'number of samples' in
|
||||||
|
one cycle of that frequency.
|
||||||
|
On failure, *result is unchanged.
|
||||||
|
return value is TRUE on success, FALSE otherwise.
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
int parsefreq(char *string, double *result);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for a switch -'string'.
|
||||||
|
return value is TRUE if one exists, FALSE otherwise.
|
||||||
|
If characters remain after the switch, a fatal error is issued.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parseswitcharg( int argcount, char *args[], char *string);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for an option starting
|
||||||
|
with 'string'. The rest of the option is read as an integer and
|
||||||
|
passed to &result.
|
||||||
|
On failure, &result is unchanged.
|
||||||
|
return value is TRUE on success, FALSE otherwise.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parseintarg( int argcount, char *args[], char *string,
|
||||||
|
int *result);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for a filename, i.e. anything
|
||||||
|
that does not start with the optionchar. The filename is copied to
|
||||||
|
newly allocated memory, a pointer to which is returned.
|
||||||
|
The argument is marked as used. Therefore repeated use of this function
|
||||||
|
will yield a complete list of filenames on the commandline.
|
||||||
|
If malloc() fails, the function does not return.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern char *parsefilearg( int argcount, char *args[]);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for an option starting
|
||||||
|
with 'string'. The rest of the option is read as a double and
|
||||||
|
passed to *result.
|
||||||
|
On failure, *result is unchanged.
|
||||||
|
return value is TRUE on success, FALSE otherwise.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parsedoublearg( int argcount, char *args[], char *string,
|
||||||
|
double *result);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for an option starting
|
||||||
|
with 'string'. The rest of the option is read as a volume, i.e.
|
||||||
|
absolute, percent or db. The result is passed to *result.
|
||||||
|
On failure, *result is unchanged.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parsevolarg( int argcount, char *args[], char *string,
|
||||||
|
double *result);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads the specified string and interprets it as a volume. The string
|
||||||
|
would be of the form 1.8 or 180% or 5db.
|
||||||
|
On success, the return value is the relative volume, i.e. 1.8
|
||||||
|
On failure, -1 is returned.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parsevolume(char *s, double *result);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads through the arguments on the lookout for a switch -'string'.
|
||||||
|
return value is TRUE if one exists, FALSE otherwise.
|
||||||
|
If characters remain after the switch, a fatal error is issued.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int parseswitch( char *found, char *wanted);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reports an error due to parsing the string 's' encountered on the
|
||||||
|
command line.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void argerror(char *s);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reports an error due to parsing the string 's' encountered on the
|
||||||
|
command line. 'code' indicates the type of error.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void argerrornum(char *s, Errornum code);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reports an error due to parsing the string 's' encountered on the
|
||||||
|
command line. 'message' explains the type of error.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void argerrortxt(char *s, char *message);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Check for any remaining arguments and complain about their existence.
|
||||||
|
If arguments are found, this function does not return.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void checknoargs( int argcount, char *args[]);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Parses the command line arguments as represented by the function
|
||||||
|
arguments. Sets the global variables 'in', 'out', 'samplefrequency'
|
||||||
|
and 'samplewidth' accordingly.
|
||||||
|
According to 'fileswitch', in and out files are opened or not. See
|
||||||
|
above for an explanation of 'fileswitch'.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void parseargs( int argcount, char *args[], int fileswitch);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Returns the index 'i' of the first argument that IS an option, and
|
||||||
|
which begins with the label 's'. If there is none, -1.
|
||||||
|
We also mark that option as done with, i.e. we cross it out.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int findoption( int argcount, char *args[], char *s);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Finishes off the .WAV header (if any) and exits correctly and formerly.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int myexit (int value);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Reads the stated input file bufferwise, calls the function 'work'
|
||||||
|
with the proper values, and writes the result to the stated output file.
|
||||||
|
Return value: TRUE on success, FALSE otherwise.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int workloop( FILE *theinfile, FILE *theoutfile,
|
||||||
|
int (*work)( short *buffer, int length) );
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Five functions for printing to stderr. Depending on the level of verbose,
|
||||||
|
output may be supressed. fatalerror() is like error() but does not return.
|
||||||
|
fatalperror() is like the standard function perror() but does not return.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int chat( const char *format, ...);
|
||||||
|
extern int inform( const char *format, ...);
|
||||||
|
extern int error( const char *format, ...);
|
||||||
|
extern void fatalerror( const char *format, ...);
|
||||||
|
extern void fatalperror( const char *string);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
And one functions for printing to stdout.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern int say( const char *format, ...);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Allocate memory for it and return a pointer to a string made up of
|
||||||
|
the two argument strings.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern char *mallocconcat( char *one, char *two);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Convert a sample value to decibel.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern double double2db( double value);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------
|
||||||
|
Read 'size' samples from file 'in' and lose them.
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
extern void readawaysamples( FILE *in, size_t size);
|
@ -0,0 +1,159 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Programs for processing sound files in raw- or WAV-format.
|
||||||
|
* -- Merge two mono WAV-files to one stereo WAV-file.
|
||||||
|
*
|
||||||
|
* Name: stereorize.c
|
||||||
|
* Version: 1.1
|
||||||
|
* Author: Mark Roberts <mark@manumark.de>
|
||||||
|
* Michael Labuschke <michael@labuschke.de>
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
static char *Version = "stereorize 1.1, November 5th 2000";
|
||||||
|
static char *Usage =
|
||||||
|
"Usage: stereorize [options] infile-left infile-right outfile\n\n"
|
||||||
|
|
||||||
|
"Example:\n"
|
||||||
|
" stereorize left.wav right.wav stereo.wav -h\n\n"
|
||||||
|
|
||||||
|
"Creates stereo.wav (with WAV-header, option -h) from data in mono files\n"
|
||||||
|
"left.wav and right.wav.\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
int main( int argcount, char *args[])
|
||||||
|
{
|
||||||
|
int i, k[2], maxk, stdin_in_use=FALSE;
|
||||||
|
short *leftsample, *rightsample, *stereosample;
|
||||||
|
FILE *channel[2];
|
||||||
|
char *filename[2], *tempname;
|
||||||
|
|
||||||
|
version = Version;
|
||||||
|
usage = Usage;
|
||||||
|
|
||||||
|
channel[0] = NULL;
|
||||||
|
channel[1] = NULL;
|
||||||
|
|
||||||
|
parseargs( argcount, args, NOFILES | NOCOMPLAIN);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
filename[i] = parsefilearg( argcount, args);
|
||||||
|
if (filename[i] == NULL)
|
||||||
|
argerrornum( NULL, ME_NOTENOUGHFILES);
|
||||||
|
if (strcmp (filename[i], "-") == 0)
|
||||||
|
{
|
||||||
|
if (stdin_in_use)
|
||||||
|
argerrortxt( filename[i] + 1,
|
||||||
|
"Cannot use <stdin> for both input files");
|
||||||
|
filename[i] = "<stdin>";
|
||||||
|
channel[i] = stdin;
|
||||||
|
stdin_in_use = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channel[i] = fopen(filename[i], "rb");
|
||||||
|
}
|
||||||
|
if (channel[i] == NULL)
|
||||||
|
fatalerror( "Error opening input file '%s': %s\n", filename[i],strerror(errno));
|
||||||
|
else
|
||||||
|
inform("Using file '%s' as input\n", filename[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
assert ( channel[i] != NULL);
|
||||||
|
readwavheader( channel[i]);
|
||||||
|
if (iswav && channels != 1)
|
||||||
|
inform("Warning: '%s' is no mono file\n", filename[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
outfilename = parsefilearg( argcount, args);
|
||||||
|
if (outfilename == NULL) argerrornum( NULL, ME_NOOUTFILE);
|
||||||
|
if (strcmp (outfilename, "-") == 0)
|
||||||
|
{
|
||||||
|
outfilename = "<stdout>";
|
||||||
|
out = stdout;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out = fopen(outfilename, "wb");
|
||||||
|
}
|
||||||
|
if (out == NULL)
|
||||||
|
fatalerror( "Error opening output file '%s': %s\n", outfilename,strerror(errno));
|
||||||
|
else
|
||||||
|
inform("Using file '%s' as output\n", outfilename);
|
||||||
|
|
||||||
|
if ((tempname = parsefilearg( argcount, args)) != NULL)
|
||||||
|
argerrornum( tempname, ME_TOOMANYFILES);
|
||||||
|
|
||||||
|
checknoargs(argcount, args); /* Check that no arguments are left */
|
||||||
|
|
||||||
|
leftsample = malloc( sizeof(*leftsample) * BUFFSIZE);
|
||||||
|
rightsample = malloc( sizeof(*leftsample) * BUFFSIZE);
|
||||||
|
stereosample = malloc( sizeof(*leftsample) * 2 * BUFFSIZE);
|
||||||
|
if (leftsample == NULL || rightsample == NULL || stereosample == NULL)
|
||||||
|
fatalperror ("");
|
||||||
|
|
||||||
|
channels = 2; /* Output files are stereo */
|
||||||
|
if (wavout)
|
||||||
|
{
|
||||||
|
if ((strcmp(outfilename,"<stdout>")!=0) && (fseek( out, 0, SEEK_SET) != 0))
|
||||||
|
fatalerror("Couldn't navigate output file '%s': %s\n",outfilename, strerror(errno));
|
||||||
|
makewavheader();
|
||||||
|
}
|
||||||
|
|
||||||
|
startstopwatch();
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
maxk = 0;
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
k[i] = fread(i==0? leftsample : rightsample,
|
||||||
|
sizeof(*leftsample),
|
||||||
|
BUFFSIZE,
|
||||||
|
channel[i]);
|
||||||
|
if (k[i] == -1)
|
||||||
|
fatalerror("Error reading file '%s': %s\n", filename[i],strerror(errno));
|
||||||
|
if (k[i] > maxk)
|
||||||
|
maxk = k[i];
|
||||||
|
}
|
||||||
|
if (maxk == 0)
|
||||||
|
myexit (0);
|
||||||
|
|
||||||
|
/*-------------------------------------------------*
|
||||||
|
* First the left channel as far as it goes ... *
|
||||||
|
*-------------------------------------------------*/
|
||||||
|
for (i = 0; i < k[0]; i++)
|
||||||
|
stereosample[2 * i] = leftsample[i];
|
||||||
|
/*-------------------------------------------------*
|
||||||
|
* ... and fill up till the end of this buffer. *
|
||||||
|
*-------------------------------------------------*/
|
||||||
|
for (; i < maxk; i++)
|
||||||
|
stereosample[2 * i] = 0;
|
||||||
|
|
||||||
|
/*-------------------------------------------------*
|
||||||
|
* Next the right channel as far as it goes ... *
|
||||||
|
*-------------------------------------------------*/
|
||||||
|
for (i = 0; i < k[1]; i++)
|
||||||
|
stereosample[2 * i + 1] = rightsample[i];
|
||||||
|
/*-------------------------------------------------*
|
||||||
|
* ... and fill up till the end of this buffer. *
|
||||||
|
*-------------------------------------------------*/
|
||||||
|
for (; i < maxk; i++)
|
||||||
|
stereosample[2 * i + 1] = 0;
|
||||||
|
|
||||||
|
fwrite(stereosample, sizeof(*leftsample), 2 * maxk, out);
|
||||||
|
if (ferror( out) != 0)
|
||||||
|
fatalerror("Error writing to file '%s': %s\n",
|
||||||
|
outfilename, strerror(errno));
|
||||||
|
}
|
||||||
|
/* That was an endless loop. This point is never reached. */
|
||||||
|
}
|
Loading…
Reference in new issue