mirror of
https://github.com/azahar-emu/soundtouch
synced 2025-11-07 07:30:02 +01:00
Allow using standard input/output pipes for processing
This commit is contained in:
parent
eb4c84fb14
commit
c7bbaa4dbe
79
README.html
79
README.html
@ -18,7 +18,7 @@
|
||||
</head>
|
||||
<body class="normal">
|
||||
<hr>
|
||||
<h1>SoundTouch audio processing library v1.3.2pre
|
||||
<h1>SoundTouch audio processing library v1.3.9 (1.4.0-pre)
|
||||
</h1>
|
||||
<p class="normal">SoundTouch library Copyright (c) Olli
|
||||
Parviainen 2002-2008 </p>
|
||||
@ -387,27 +387,29 @@ processing sound files.</p>
|
||||
<h3>4.1. SoundStretch Usage Instructions</h3>
|
||||
<p>SoundStretch Usage syntax:</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch infile.wav outfile.wav [switches]</pre>
|
||||
<pre>soundstretch infilename outfilename [switches]</pre>
|
||||
</blockquote>
|
||||
<p>Where: </p>
|
||||
<table border="0" cellpadding="2" width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<pre>"infile.wav"</pre>
|
||||
<pre>"infilename"</pre>
|
||||
</td>
|
||||
<td valign="top">is the name of the input sound
|
||||
data file (in .WAV audio file format). </td>
|
||||
<td valign="top">Name of the input sound
|
||||
data file (in .WAV audio file format). Give "stdin" as filename to use
|
||||
standard input pipe. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<pre>"outfile.wav"</pre>
|
||||
<pre>"outfilename"</pre>
|
||||
</td>
|
||||
<td valign="top">is the name of the output sound
|
||||
<td valign="top">Name of the output sound
|
||||
file where the resulting sound is saved (in .WAV audio file format).
|
||||
This parameter may be omitted if you don't want to save the
|
||||
output
|
||||
(e.g. when only calculating BPM rate with '-bpm' switch).</td>
|
||||
(e.g. when only calculating BPM rate with '-bpm' switch). Give "stdout"
|
||||
as filename to use standard output pipe.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
@ -447,10 +449,10 @@ n percents (n = -95.0 .. +5000.0 %) </td>
|
||||
<pre>-bpm=n</pre>
|
||||
</td>
|
||||
<td valign="top">Detect the Beats-Per-Minute
|
||||
(BPM) rate of the sound and adjust the tempo to meet 'n' BPMs. If this
|
||||
switch is defined, the "-tempo=n" switch value is ignored. If "=n" is
|
||||
omitted, i.e. switch "-bpm" is used alone, the program just calculates
|
||||
and displays the BPM rate but doesn't adjust tempo according to the BPM
|
||||
(BPM) rate of the sound and adjust the tempo to meet 'n' BPMs. When this switch is
|
||||
applied, the "-tempo" switch is ignored. If "=n" is
|
||||
omitted, i.e. switch "-bpm" is used alone, then the BPM rate is
|
||||
estimated and displayed, but tempo not adjusted according to the BPM
|
||||
value. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -479,59 +481,61 @@ text (LGPL)</td>
|
||||
</table>
|
||||
<p>Notes:</p>
|
||||
<ul>
|
||||
<li>The numerical switch values can be entered
|
||||
using either integer (e.g. "-tempo=123") or decimal (e.g.
|
||||
<li>To use standard input/output pipes for processing, give "stdin"
|
||||
and "stdout" as input/output filenames correspondingly. The
|
||||
standard input/output pipes will still carry the audio data in .wav audio
|
||||
file format.</li>
|
||||
<li>The numerical switches allow both integer (e.g. "-tempo=123") and decimal (e.g.
|
||||
"-tempo=123.45") numbers.</li>
|
||||
<li>The "-naa" and/or "-quick" switches can be
|
||||
used to reduce CPU usage while compromising some sound quality </li>
|
||||
<li>The BPM detection algorithm works by detecting
|
||||
repeating low-frequency (<250H) sound patterns and thus works
|
||||
mostly with most rock/pop music with bass or drum beat. The BPM
|
||||
detection doesn't work on pieces such as classical music without
|
||||
distinct, repeating bass frequency patterns. Also pieces with varying
|
||||
tempo, varying bass patterns or very complex bass patterns (ja, hiphop) may produce odd BPM readings. <br>
|
||||
<br>
|
||||
In cases when the bass pattern drifts a bit around a nominal beat rate
|
||||
(e.g. drummer is again drunken :), the BPM algorithm may report
|
||||
incorrect harmonic one-halft to one-thirdth of the correct BPM value;
|
||||
in such case the system could for example report BPM value of 50 or 100
|
||||
instead of correct BPM value of 150. </li>
|
||||
repeating bass or drum patterns at low frequencies of <250Hz. A
|
||||
lower-than-expected BPM figure may be reported for music with uneven or
|
||||
complex bass patterns. </li>
|
||||
</ul>
|
||||
<h3>4.2. SoundStretch usage examples </h3>
|
||||
<p><strong>Example 1</strong></p>
|
||||
<p>The following command increases tempo of
|
||||
the sound file "originalfile.wav" by 12.5% and saves
|
||||
result to file "destinationfile.wav":</p>
|
||||
the sound file "originalfile.wav" by 12.5% and stores result to file "destinationfile.wav":</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch originalfile.wav destinationfile.wav -tempo=12.5</pre>
|
||||
</blockquote>
|
||||
<p><strong>Example 2</strong></p>
|
||||
<p>The following command decreases the sound
|
||||
pitch (key) of the sound file "orig.wav" by two
|
||||
semitones and saves the result to file "dest.wav":</p>
|
||||
semitones and stores the result to file "dest.wav":</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch orig.wav dest.wav -pitch=-2</pre>
|
||||
</blockquote>
|
||||
<p><strong>Example 3</strong></p>
|
||||
<p>The following command processes the file "orig.wav" by decreasing the sound tempo by 25.3% and
|
||||
increasing the sound pitch (key) by 1.5 semitones. Result is
|
||||
saved to file "dest.wav":</p>
|
||||
increasing the sound pitch (key) by 1.5 semitones. Resulting .wav audio data is
|
||||
directed to standard output pipe:</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch orig.wav dest.wav -tempo=-25.3 -pitch=1.5</pre>
|
||||
<pre>soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5</pre>
|
||||
</blockquote>
|
||||
<p><strong>Example 4</strong></p>
|
||||
<p>The following command detects the BPM rate
|
||||
of the file "orig.wav" and adjusts the tempo to match
|
||||
100 beats per minute. Result is saved to file "dest.wav":</p>
|
||||
100 beats per minute. Result is stored to file "dest.wav":</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch orig.wav dest.wav -bpm=100</pre>
|
||||
</blockquote>
|
||||
<p><strong>Example 5</strong></p>
|
||||
<p>The following command reads .wav sound data from standard input pipe and
|
||||
estimates the BPM rate:</p>
|
||||
<blockquote>
|
||||
<pre>soundstretch stdin -bpm</pre>
|
||||
</blockquote>
|
||||
<hr>
|
||||
<h2>5. Change History</h2>
|
||||
<h3>5.1. SoundTouch library Change History </h3>
|
||||
|
||||
<p><strong>v1.3.2:</strong></p>
|
||||
<p><strong>v1.3.9 (1.4.0 pre):</strong></p>
|
||||
<ul>
|
||||
<li>Moved BPM detection routines from SoundStretch application into SoundTouch
|
||||
library</li>
|
||||
<li>Bugfixes: Using uninitialied variables, GNU build scripts, compiler errors
|
||||
due to 'const' keyword mismatch.</li>
|
||||
<li>Some source code cleanup</li>
|
||||
@ -617,6 +621,15 @@ files. </li>
|
||||
<p> </p>
|
||||
<h3>5.2. SoundStretch application Change
|
||||
History </h3>
|
||||
|
||||
<p><strong>v1.3.9 (1.4.0 pre):</strong></p>
|
||||
<ul>
|
||||
<li>Moved BPM detection routines from SoundStretch application into SoundTouch
|
||||
library</li>
|
||||
<li>Allow using standard input/output pipes for processing </li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p><strong>v1.3.0:</strong></p>
|
||||
<ul>
|
||||
<li>Simplified accessing WAV files with floating
|
||||
|
||||
@ -77,7 +77,10 @@ static const char whatText[] =
|
||||
|
||||
static const char usage[] =
|
||||
"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"
|
||||
" -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"
|
||||
|
||||
@ -140,8 +140,6 @@ const static char dataStr[] = "data";
|
||||
|
||||
WavInFile::WavInFile(const char *fileName)
|
||||
{
|
||||
int hdrsOk;
|
||||
|
||||
// Try to open the file for reading
|
||||
fptr = fopen(fileName, "rb");
|
||||
if (fptr == NULL)
|
||||
@ -153,22 +151,45 @@ WavInFile::WavInFile(const char *fileName)
|
||||
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
|
||||
hdrsOk = readWavHeaders();
|
||||
if (hdrsOk != 0)
|
||||
{
|
||||
// Something didn't match in the wav file headers
|
||||
string msg = "File \"";
|
||||
msg += fileName;
|
||||
msg += "\" is corrupt or not a WAV file";
|
||||
string msg = "Input file is corrupt or not a WAV file";
|
||||
throw runtime_error(msg);
|
||||
}
|
||||
|
||||
if (header.format.fixed != 1)
|
||||
{
|
||||
string msg = "File \"";
|
||||
msg += fileName;
|
||||
msg += "\" uses unsupported encoding.";
|
||||
string msg = "Input file uses unsupported encoding.";
|
||||
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()
|
||||
{
|
||||
|
||||
@ -105,6 +105,9 @@ private:
|
||||
/// WAV header information
|
||||
WavHeader header;
|
||||
|
||||
/// Init the WAV file stream
|
||||
void init();
|
||||
|
||||
/// Read WAV file headers.
|
||||
/// \return zero if all ok, nonzero if file format is invalid.
|
||||
int readWavHeaders();
|
||||
@ -125,6 +128,8 @@ public:
|
||||
/// throws 'runtime_error' exception.
|
||||
WavInFile(const char *filename);
|
||||
|
||||
WavInFile(FILE *file);
|
||||
|
||||
/// Destructor: Closes the file.
|
||||
~WavInFile();
|
||||
|
||||
@ -222,6 +227,8 @@ public:
|
||||
int channels ///< Number of channels (1=mono, 2=stereo)
|
||||
);
|
||||
|
||||
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
|
||||
|
||||
/// Destructor: Finalizes & closes the WAV file.
|
||||
~WavOutFile();
|
||||
|
||||
|
||||
@ -49,12 +49,25 @@ using namespace std;
|
||||
// Processing chunk size
|
||||
#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[] =
|
||||
"\n"
|
||||
" SoundStretch v%s - Written by Olli Parviainen 2001 - 2008\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"
|
||||
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
|
||||
"more information.\n"
|
||||
@ -64,8 +77,17 @@ static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParamet
|
||||
{
|
||||
int bits, samplerate, channels;
|
||||
|
||||
if (strcmp(params->inFileName, "stdin") == 0)
|
||||
{
|
||||
// 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
|
||||
bits = (*inFile)->getNumBits();
|
||||
@ -73,9 +95,17 @@ static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParamet
|
||||
channels = (*inFile)->getNumChannels();
|
||||
|
||||
if (params->outFileName)
|
||||
{
|
||||
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
|
||||
{
|
||||
*outFile = NULL;
|
||||
@ -107,27 +137,27 @@ static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunPar
|
||||
if (params->outFileName)
|
||||
{
|
||||
#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
|
||||
#ifndef FLOAT_SAMPLES
|
||||
#error "Sampletype not defined"
|
||||
#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
|
||||
// print processing information only if outFileName given i.e. some processing will happen
|
||||
printf("Processing the file with the following changes:\n");
|
||||
printf(" tempo change = %+g %%\n", params->tempoDelta);
|
||||
printf(" pitch change = %+g semitones\n", params->pitchDelta);
|
||||
printf(" rate change = %+g %%\n\n", params->rateDelta);
|
||||
printf("Working...");
|
||||
fprintf(stderr, "Processing the file with the following changes:\n");
|
||||
fprintf(stderr, " tempo change = %+g %%\n", params->tempoDelta);
|
||||
fprintf(stderr, " pitch change = %+g semitones\n", params->pitchDelta);
|
||||
fprintf(stderr, " rate change = %+g %%\n\n", params->rateDelta);
|
||||
fprintf(stderr, "Working...");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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];
|
||||
|
||||
// detect bpm rate
|
||||
printf("Detecting BPM rate...");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Detecting BPM rate...");
|
||||
fflush(stderr);
|
||||
|
||||
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.
|
||||
bpmValue = bpm.getBpm();
|
||||
printf("Done!\n");
|
||||
fprintf(stderr, "Done!\n");
|
||||
|
||||
// rewind the file after bpm detection
|
||||
inFile->rewind();
|
||||
|
||||
if (bpmValue > 0)
|
||||
{
|
||||
printf("Detected BPM rate %.1f\n\n", bpmValue);
|
||||
fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Couldn't detect BPM rate.\n\n");
|
||||
fprintf(stderr, "Couldn't detect BPM rate.\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,7 +264,7 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
|
||||
{
|
||||
// adjust tempo to given bpm
|
||||
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;
|
||||
SoundTouch SoundTouch;
|
||||
|
||||
printf(_helloText, SoundTouch::getVersionString());
|
||||
fprintf(stderr, _helloText, SoundTouch::getVersionString());
|
||||
|
||||
try
|
||||
{
|
||||
@ -275,12 +305,12 @@ int main(const int nParams, const char *paramStr[])
|
||||
delete outFile;
|
||||
delete params;
|
||||
|
||||
printf("Done!\n");
|
||||
fprintf(stderr, "Done!\n");
|
||||
}
|
||||
catch (runtime_error &e)
|
||||
{
|
||||
// An exception occurred during processing, display an error message
|
||||
printf("%s\n", e.what());
|
||||
fprintf(stderr, "%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user