Allow using standard input/output pipes for processing

This commit is contained in:
oparviai 2008-12-25 12:38:45 +00:00
parent eb4c84fb14
commit c7bbaa4dbe
5 changed files with 813 additions and 724 deletions

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,10 @@ static const char whatText[] =
static const char usage[] = static const char usage[] =
"Usage :\n" "Usage :\n"
" soundstretch infile.wav outfile.wav [switches]\n\n" " soundstretch infilename outfilename [switches]\n"
"\n"
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
"\n"
"Available switches are:\n" "Available switches are:\n"
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n" " -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n" " -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"

View File

@ -140,8 +140,6 @@ const static char dataStr[] = "data";
WavInFile::WavInFile(const char *fileName) WavInFile::WavInFile(const char *fileName)
{ {
int hdrsOk;
// Try to open the file for reading // Try to open the file for reading
fptr = fopen(fileName, "rb"); fptr = fopen(fileName, "rb");
if (fptr == NULL) if (fptr == NULL)
@ -153,22 +151,45 @@ WavInFile::WavInFile(const char *fileName)
throw runtime_error(msg); throw runtime_error(msg);
} }
init();
}
WavInFile::WavInFile(FILE *file)
{
// Try to open the file for reading
fptr = file;
if (!file)
{
// didn't succeed
string msg = "Error : Unable to access input stream for reading";
throw runtime_error(msg);
}
init();
}
/// Init the WAV file stream
void WavInFile::init()
{
int hdrsOk;
// assume file stream is already open
assert(fptr);
// Read the file headers // Read the file headers
hdrsOk = readWavHeaders(); hdrsOk = readWavHeaders();
if (hdrsOk != 0) if (hdrsOk != 0)
{ {
// Something didn't match in the wav file headers // Something didn't match in the wav file headers
string msg = "File \""; string msg = "Input file is corrupt or not a WAV file";
msg += fileName;
msg += "\" is corrupt or not a WAV file";
throw runtime_error(msg); throw runtime_error(msg);
} }
if (header.format.fixed != 1) if (header.format.fixed != 1)
{ {
string msg = "File \""; string msg = "Input file uses unsupported encoding.";
msg += fileName;
msg += "\" uses unsupported encoding.";
throw runtime_error(msg); throw runtime_error(msg);
} }
@ -537,6 +558,21 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
} }
WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
{
bytesWritten = 0;
fptr = file;
if (fptr == NULL)
{
string msg = "Error : Unable to access output file stream.";
throw runtime_error(msg);
}
fillInHeader(sampleRate, bits, channels);
writeHeader();
}
WavOutFile::~WavOutFile() WavOutFile::~WavOutFile()
{ {

View File

@ -105,6 +105,9 @@ private:
/// WAV header information /// WAV header information
WavHeader header; WavHeader header;
/// Init the WAV file stream
void init();
/// Read WAV file headers. /// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid. /// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders(); int readWavHeaders();
@ -125,6 +128,8 @@ public:
/// throws 'runtime_error' exception. /// throws 'runtime_error' exception.
WavInFile(const char *filename); WavInFile(const char *filename);
WavInFile(FILE *file);
/// Destructor: Closes the file. /// Destructor: Closes the file.
~WavInFile(); ~WavInFile();
@ -222,6 +227,8 @@ public:
int channels ///< Number of channels (1=mono, 2=stereo) int channels ///< Number of channels (1=mono, 2=stereo)
); );
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
/// Destructor: Finalizes & closes the WAV file. /// Destructor: Finalizes & closes the WAV file.
~WavOutFile(); ~WavOutFile();

View File

@ -49,12 +49,25 @@ using namespace std;
// Processing chunk size // Processing chunk size
#define BUFF_SIZE 2048 #define BUFF_SIZE 2048
#if WIN32
#include <io.h>
#include <fcntl.h>
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(fileno(f), _O_BINARY))
#else
// Not needed for GNU environment... ?
#define SET_STREAM_TO_BIN_MODE(f) ()
#endif
static const char _helloText[] = static const char _helloText[] =
"\n" "\n"
" SoundStretch v%s - Written by Olli Parviainen 2001 - 2008\n" " SoundStretch v%s - Written by Olli Parviainen 2001 - 2008\n"
"==================================================================\n" "==================================================================\n"
"author e-mail: <oparviai@iki.fi> - WWW: http://www.surina.net/soundtouch\n" "author e-mail: <oparviai"
"@"
"iki.fi> - WWW: http://www.surina.net/soundtouch\n"
"\n" "\n"
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n" "This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
"more information.\n" "more information.\n"
@ -64,8 +77,17 @@ static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParamet
{ {
int bits, samplerate, channels; int bits, samplerate, channels;
// open input file... if (strcmp(params->inFileName, "stdin") == 0)
*inFile = new WavInFile(params->inFileName); {
// used 'stdin' as input file
SET_STREAM_TO_BIN_MODE(stdin);
*inFile = new WavInFile(stdin);
}
else
{
// open input file...
*inFile = new WavInFile(params->inFileName);
}
// ... open output file with same sound parameters // ... open output file with same sound parameters
bits = (*inFile)->getNumBits(); bits = (*inFile)->getNumBits();
@ -74,7 +96,15 @@ static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParamet
if (params->outFileName) if (params->outFileName)
{ {
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels); if (strcmp(params->outFileName, "stdout") == 0)
{
SET_STREAM_TO_BIN_MODE(stdout);
*outFile = new WavOutFile(stdout, samplerate, bits, channels);
}
else
{
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels);
}
} }
else else
{ {
@ -107,27 +137,27 @@ static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunPar
if (params->outFileName) if (params->outFileName)
{ {
#ifdef INTEGER_SAMPLES #ifdef INTEGER_SAMPLES
printf("Uses 16bit integer sample type in processing.\n\n"); fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
#else #else
#ifndef FLOAT_SAMPLES #ifndef FLOAT_SAMPLES
#error "Sampletype not defined" #error "Sampletype not defined"
#endif #endif
printf("Uses 32bit floating point sample type in processing.\n\n"); fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
#endif #endif
// print processing information only if outFileName given i.e. some processing will happen // print processing information only if outFileName given i.e. some processing will happen
printf("Processing the file with the following changes:\n"); fprintf(stderr, "Processing the file with the following changes:\n");
printf(" tempo change = %+g %%\n", params->tempoDelta); fprintf(stderr, " tempo change = %+g %%\n", params->tempoDelta);
printf(" pitch change = %+g semitones\n", params->pitchDelta); fprintf(stderr, " pitch change = %+g semitones\n", params->pitchDelta);
printf(" rate change = %+g %%\n\n", params->rateDelta); fprintf(stderr, " rate change = %+g %%\n\n", params->rateDelta);
printf("Working..."); fprintf(stderr, "Working...");
} }
else else
{ {
// outFileName not given // outFileName not given
printf("Warning: output file name missing, won't output anything.\n\n"); fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
} }
fflush(stdout); fflush(stderr);
} }
@ -194,8 +224,8 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
// detect bpm rate // detect bpm rate
printf("Detecting BPM rate..."); fprintf(stderr, "Detecting BPM rate...");
fflush(stdout); fflush(stderr);
nChannels = inFile->getNumChannels(); nChannels = inFile->getNumChannels();
@ -215,18 +245,18 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
// Now the whole song data has been analyzed. Read the resulting bpm. // Now the whole song data has been analyzed. Read the resulting bpm.
bpmValue = bpm.getBpm(); bpmValue = bpm.getBpm();
printf("Done!\n"); fprintf(stderr, "Done!\n");
// rewind the file after bpm detection // rewind the file after bpm detection
inFile->rewind(); inFile->rewind();
if (bpmValue > 0) if (bpmValue > 0)
{ {
printf("Detected BPM rate %.1f\n\n", bpmValue); fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);
} }
else else
{ {
printf("Couldn't detect BPM rate.\n\n"); fprintf(stderr, "Couldn't detect BPM rate.\n\n");
return; return;
} }
@ -234,7 +264,7 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
{ {
// adjust tempo to given bpm // adjust tempo to given bpm
params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f; params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f;
printf("The file will be converted to %.1f BPM\n\n", params->goalBPM); fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM);
} }
} }
@ -247,7 +277,7 @@ int main(const int nParams, const char *paramStr[])
RunParameters *params; RunParameters *params;
SoundTouch SoundTouch; SoundTouch SoundTouch;
printf(_helloText, SoundTouch::getVersionString()); fprintf(stderr, _helloText, SoundTouch::getVersionString());
try try
{ {
@ -275,12 +305,12 @@ int main(const int nParams, const char *paramStr[])
delete outFile; delete outFile;
delete params; delete params;
printf("Done!\n"); fprintf(stderr, "Done!\n");
} }
catch (runtime_error &e) catch (runtime_error &e)
{ {
// An exception occurred during processing, display an error message // An exception occurred during processing, display an error message
printf("%s\n", e.what()); fprintf(stderr, "%s\n", e.what());
return -1; return -1;
} }