mirror of
https://github.com/azahar-emu/soundtouch
synced 2025-11-06 23:20:03 +01:00
Windows: SoundStretch to accept wide-character command line attributes to support asian/non-latin files names.
This commit is contained in:
parent
74514f5597
commit
375e6ccfe9
@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(SoundTouch VERSION 2.3.2 LANGUAGES CXX)
|
||||
project(SoundTouch VERSION 2.3.3 LANGUAGES CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<body class="normal">
|
||||
<hr>
|
||||
<h1>SoundTouch audio processing library v2.3.2</h1>
|
||||
<p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2022</p>
|
||||
<p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2024</p>
|
||||
<hr>
|
||||
<h2>1. Introduction </h2>
|
||||
<p>SoundTouch is an open-source audio processing library that allows
|
||||
@ -450,7 +450,7 @@
|
||||
<h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility
|
||||
</h2>
|
||||
<p>SoundStretch audio processing utility<br>
|
||||
Copyright (c) Olli Parviainen 2002-2022</p>
|
||||
Copyright (c) Olli Parviainen 2002-2024</p>
|
||||
<p>SoundStretch is a simple command-line application that can change
|
||||
tempo, pitch and playback rates of WAV sound files. This program is
|
||||
intended primarily to demonstrate how the "SoundTouch" library can be
|
||||
@ -874,6 +874,10 @@
|
||||
<li> Initial release</li>
|
||||
</ul>
|
||||
<h3>5.2. SoundStretch application Change History </h3>
|
||||
<p><b>2.3.3:</b></p>
|
||||
<ul>
|
||||
<li>Added support for Asian / non-latin filenames in Windows. Gnu platform has supported them already earlier.</li>
|
||||
</ul>
|
||||
<p><b>1.9:</b></p>
|
||||
<ul>
|
||||
<li>Added support for WAV file 'fact' information chunk.</li>
|
||||
|
||||
@ -72,10 +72,10 @@ namespace soundtouch
|
||||
{
|
||||
|
||||
/// Soundtouch library version string
|
||||
#define SOUNDTOUCH_VERSION "2.3.2"
|
||||
#define SOUNDTOUCH_VERSION "2.3.3"
|
||||
|
||||
/// SoundTouch library version id
|
||||
#define SOUNDTOUCH_VERSION_ID (20302)
|
||||
#define SOUNDTOUCH_VERSION_ID (20303)
|
||||
|
||||
//
|
||||
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||
|
||||
@ -30,12 +30,15 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "RunParameters.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace soundstretch
|
||||
{
|
||||
|
||||
// Program usage instructions
|
||||
|
||||
static const char licenseText[] =
|
||||
@ -94,9 +97,8 @@ static int _toLowerCase(int c)
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// Constructor
|
||||
RunParameters::RunParameters(const int nParams, const char * const paramStr[])
|
||||
RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[])
|
||||
{
|
||||
int i;
|
||||
int nFirstParam;
|
||||
@ -112,28 +114,17 @@ RunParameters::RunParameters(const int nParams, const char * const paramStr[])
|
||||
}
|
||||
string msg = whatText;
|
||||
msg += usage;
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
throw(msg);
|
||||
}
|
||||
|
||||
inFileName = nullptr;
|
||||
outFileName = nullptr;
|
||||
tempoDelta = 0;
|
||||
pitchDelta = 0;
|
||||
rateDelta = 0;
|
||||
quick = 0;
|
||||
noAntiAlias = 0;
|
||||
goalBPM = 0;
|
||||
speech = false;
|
||||
detectBPM = false;
|
||||
|
||||
// Get input & output file names
|
||||
inFileName = (char*)paramStr[1];
|
||||
outFileName = (char*)paramStr[2];
|
||||
inFileName = paramStr[1];
|
||||
outFileName = paramStr[2];
|
||||
|
||||
if (outFileName[0] == '-')
|
||||
{
|
||||
// no outputfile name was given but parameters
|
||||
outFileName = nullptr;
|
||||
// outputfile name was omitted but other parameter switches given instead
|
||||
outFileName = STRING_CONST("");
|
||||
nFirstParam = 2;
|
||||
}
|
||||
else
|
||||
@ -182,25 +173,33 @@ void RunParameters::checkLimits()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unknown switch parameter -- throws an exception with an error message
|
||||
void RunParameters::throwIllegalParamExp(const string &str) const
|
||||
// Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible
|
||||
std::string convertString(const STRING& str)
|
||||
{
|
||||
string msg = "ERROR : Illegal parameter \"";
|
||||
msg += str;
|
||||
msg += "\".\n\n";
|
||||
msg += usage;
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
std::string res;
|
||||
for (auto c : str)
|
||||
{
|
||||
res += (char)c;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Unknown switch parameter -- throws an exception with an error message
|
||||
void RunParameters::throwIllegalParamExp(const STRING &str) const
|
||||
{
|
||||
string msg = "ERROR : Illegal parameter \"";
|
||||
msg += convertString(str);
|
||||
msg += "\".\n\n";
|
||||
msg += usage;
|
||||
ST_THROW_RT_ERROR(msg);
|
||||
}
|
||||
|
||||
void RunParameters::throwLicense() const
|
||||
{
|
||||
ST_THROW_RT_ERROR(licenseText);
|
||||
}
|
||||
|
||||
|
||||
float RunParameters::parseSwitchValue(const string &str) const
|
||||
float RunParameters::parseSwitchValue(const STRING& str) const
|
||||
{
|
||||
int pos;
|
||||
|
||||
@ -212,14 +211,14 @@ float RunParameters::parseSwitchValue(const string &str) const
|
||||
}
|
||||
|
||||
// Read numerical parameter value after '='
|
||||
return (float)atof(str.substr(pos + 1).c_str());
|
||||
return (float)stof(str.substr(pos + 1).c_str());
|
||||
}
|
||||
|
||||
|
||||
// Interprets a single switch parameter string of format "-switch=xx"
|
||||
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
|
||||
// switch values into 'params' structure.
|
||||
void RunParameters::parseSwitchParam(const string &str)
|
||||
void RunParameters::parseSwitchParam(const STRING& str)
|
||||
{
|
||||
int upS;
|
||||
|
||||
@ -289,3 +288,5 @@ void RunParameters::parseSwitchParam(const string &str)
|
||||
throwIllegalParamExp(str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -32,34 +32,39 @@
|
||||
#ifndef RUNPARAMETERS_H
|
||||
#define RUNPARAMETERS_H
|
||||
|
||||
#include "STTypes.h"
|
||||
#include <string>
|
||||
#include "STTypes.h"
|
||||
#include "SS_CharTypes.h"
|
||||
#include "WavFile.h"
|
||||
|
||||
using namespace std;
|
||||
namespace soundstretch
|
||||
{
|
||||
|
||||
/// Parses command line parameters into program parameters
|
||||
class RunParameters
|
||||
{
|
||||
private:
|
||||
void throwIllegalParamExp(const string &str) const;
|
||||
void throwIllegalParamExp(const STRING& str) const;
|
||||
void throwLicense() const;
|
||||
void parseSwitchParam(const string &str);
|
||||
void parseSwitchParam(const STRING& str);
|
||||
void checkLimits();
|
||||
float parseSwitchValue(const string &str) const;
|
||||
float parseSwitchValue(const STRING& tr) const;
|
||||
|
||||
public:
|
||||
char *inFileName;
|
||||
char *outFileName;
|
||||
float tempoDelta;
|
||||
float pitchDelta;
|
||||
float rateDelta;
|
||||
int quick;
|
||||
int noAntiAlias;
|
||||
float goalBPM;
|
||||
bool detectBPM;
|
||||
bool speech;
|
||||
STRING inFileName;
|
||||
STRING outFileName;
|
||||
float tempoDelta{ 0 };
|
||||
float pitchDelta{ 0 };
|
||||
float rateDelta{ 0 };
|
||||
int quick{ 0 };
|
||||
int noAntiAlias{ 0 };
|
||||
float goalBPM{ 0 };
|
||||
bool detectBPM{ false };
|
||||
bool speech{ false };
|
||||
|
||||
RunParameters(const int nParams, const char * const paramStr[]);
|
||||
RunParameters(int nParams, const CHARTYPE* paramStr[]);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -42,14 +42,23 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
#include "WavFile.h"
|
||||
#include "STTypes.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace soundstretch
|
||||
{
|
||||
|
||||
#if _WIN32
|
||||
#define FOPEN(name, mode) _wfopen(name, STRING_CONST(mode))
|
||||
#else
|
||||
#define FOPEN(name, mode) fopen(name, mode)
|
||||
#endif
|
||||
|
||||
static const char riffStr[] = "RIFF";
|
||||
static const char waveStr[] = "WAVE";
|
||||
static const char fmtStr[] = "fmt ";
|
||||
@ -169,17 +178,13 @@ void *WavFileBase::getConvBuffer(int sizeBytes)
|
||||
// Class WavInFile
|
||||
//
|
||||
|
||||
WavInFile::WavInFile(const char *fileName)
|
||||
WavInFile::WavInFile(const STRING& fileName)
|
||||
{
|
||||
// Try to open the file for reading
|
||||
fptr = fopen(fileName, "rb");
|
||||
fptr = FOPEN(fileName.c_str(), "rb");
|
||||
if (fptr == nullptr)
|
||||
{
|
||||
// didn't succeed
|
||||
string msg = "Error : Unable to open file \"";
|
||||
msg += fileName;
|
||||
msg += "\" for reading.";
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
ST_THROW_RT_ERROR("Error : Unable to open file for reading.");
|
||||
}
|
||||
|
||||
init();
|
||||
@ -192,9 +197,7 @@ WavInFile::WavInFile(FILE *file)
|
||||
fptr = file;
|
||||
if (!file)
|
||||
{
|
||||
// didn't succeed
|
||||
string msg = "Error : Unable to access input stream for reading";
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
ST_THROW_RT_ERROR("Error : Unable to access input stream for reading");
|
||||
}
|
||||
|
||||
init();
|
||||
@ -213,7 +216,6 @@ void WavInFile::init()
|
||||
hdrsOk = readWavHeaders();
|
||||
if (hdrsOk != 0)
|
||||
{
|
||||
// Something didn't match in the wav file headers
|
||||
ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
|
||||
}
|
||||
|
||||
@ -223,7 +225,6 @@ void WavInFile::init()
|
||||
(header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||
|
||||
(header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))
|
||||
{
|
||||
// Something didn't match in the wav file headers
|
||||
ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
|
||||
}
|
||||
|
||||
@ -703,17 +704,13 @@ uint WavInFile::getElapsedMS() const
|
||||
// Class WavOutFile
|
||||
//
|
||||
|
||||
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
|
||||
WavOutFile::WavOutFile(const STRING& fileName, int sampleRate, int bits, int channels)
|
||||
{
|
||||
bytesWritten = 0;
|
||||
fptr = fopen(fileName, "wb");
|
||||
fptr = FOPEN(fileName.c_str(), "wb");
|
||||
if (fptr == nullptr)
|
||||
{
|
||||
string msg = "Error : Unable to open file \"";
|
||||
msg += fileName;
|
||||
msg += "\" for writing.";
|
||||
//pmsg = msg.c_str;
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
ST_THROW_RT_ERROR("Error : Unable to open file for writing.");
|
||||
}
|
||||
|
||||
fillInHeader(sampleRate, bits, channels);
|
||||
@ -727,8 +724,7 @@ WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
|
||||
fptr = file;
|
||||
if (fptr == nullptr)
|
||||
{
|
||||
string msg = "Error : Unable to access output file stream.";
|
||||
ST_THROW_RT_ERROR(msg.c_str());
|
||||
ST_THROW_RT_ERROR("Error : Unable to access output file stream.");
|
||||
}
|
||||
|
||||
fillInHeader(sampleRate, bits, channels);
|
||||
@ -875,7 +871,7 @@ void WavOutFile::write(const short *buffer, int numElems)
|
||||
|
||||
// use temp buffer to swap byte order if necessary
|
||||
short* pTemp = (short*)getConvBuffer(numElems * sizeof(short));
|
||||
memcpy(pTemp, buffer, numElems * 2);
|
||||
memcpy(pTemp, buffer, (size_t)numElems * 2L);
|
||||
_swap16Buffer(pTemp, numElems);
|
||||
|
||||
res = (int)fwrite(pTemp, 2, numElems, fptr);
|
||||
@ -984,3 +980,5 @@ void WavOutFile::write(const float *buffer, int numElems)
|
||||
}
|
||||
bytesWritten += numBytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -40,7 +40,12 @@
|
||||
#ifndef WAVFILE_H
|
||||
#define WAVFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "SS_CharTypes.h"
|
||||
|
||||
namespace soundstretch
|
||||
{
|
||||
|
||||
#ifndef uint
|
||||
typedef unsigned int uint;
|
||||
@ -145,7 +150,7 @@ private:
|
||||
public:
|
||||
/// Constructor: Opens the given WAV file. If the file can't be opened,
|
||||
/// throws 'runtime_error' exception.
|
||||
WavInFile(const char *filename);
|
||||
WavInFile(const STRING& filename);
|
||||
|
||||
WavInFile(FILE *file);
|
||||
|
||||
@ -241,7 +246,7 @@ private:
|
||||
public:
|
||||
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
|
||||
/// if file creation fails.
|
||||
WavOutFile(const char *fileName, ///< Filename
|
||||
WavOutFile(const STRING& fileName, ///< Filename
|
||||
int sampleRate, ///< Sample rate (e.g. 44100 etc)
|
||||
int bits, ///< Bits per sample (8 or 16 bits)
|
||||
int channels ///< Number of channels (1=mono, 2=stereo)
|
||||
@ -271,4 +276,6 @@ public:
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -29,10 +29,12 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include "RunParameters.h"
|
||||
#include "WavFile.h"
|
||||
#include "SoundTouch.h"
|
||||
@ -41,6 +43,9 @@
|
||||
using namespace soundtouch;
|
||||
using namespace std;
|
||||
|
||||
namespace soundstretch
|
||||
{
|
||||
|
||||
// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)
|
||||
#define BUFF_SIZE 6720
|
||||
|
||||
@ -68,76 +73,67 @@ static const char _helloText[] =
|
||||
"more information.\n"
|
||||
"\n";
|
||||
|
||||
static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params)
|
||||
static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params)
|
||||
{
|
||||
int bits, samplerate, channels;
|
||||
|
||||
if (strcmp(params->inFileName, "stdin") == 0)
|
||||
if (params.inFileName == STRING_CONST("stdin"))
|
||||
{
|
||||
// used 'stdin' as input file
|
||||
SET_STREAM_TO_BIN_MODE(stdin);
|
||||
*inFile = new WavInFile(stdin);
|
||||
inFile = make_unique<WavInFile>(stdin);
|
||||
}
|
||||
else
|
||||
{
|
||||
// open input file...
|
||||
*inFile = new WavInFile(params->inFileName);
|
||||
inFile = make_unique<WavInFile>(params.inFileName.c_str());
|
||||
}
|
||||
|
||||
// ... open output file with same sound parameters
|
||||
bits = (int)(*inFile)->getNumBits();
|
||||
samplerate = (int)(*inFile)->getSampleRate();
|
||||
channels = (int)(*inFile)->getNumChannels();
|
||||
const int bits = (int)inFile->getNumBits();
|
||||
const int samplerate = (int)inFile->getSampleRate();
|
||||
const int channels = (int)inFile->getNumChannels();
|
||||
|
||||
if (params->outFileName)
|
||||
if (!params.outFileName.empty())
|
||||
{
|
||||
if (strcmp(params->outFileName, "stdout") == 0)
|
||||
if (params.outFileName == STRING_CONST("stdout"))
|
||||
{
|
||||
SET_STREAM_TO_BIN_MODE(stdout);
|
||||
*outFile = new WavOutFile(stdout, samplerate, bits, channels);
|
||||
outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels);
|
||||
}
|
||||
else
|
||||
{
|
||||
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels);
|
||||
outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*outFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sets the 'SoundTouch' object up according to input file sound format &
|
||||
// command line parameters
|
||||
static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params)
|
||||
static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params)
|
||||
{
|
||||
int sampleRate;
|
||||
int channels;
|
||||
const int sampleRate = (int)inFile.getSampleRate();
|
||||
const int channels = (int)inFile.getNumChannels();
|
||||
soundTouch.setSampleRate(sampleRate);
|
||||
soundTouch.setChannels(channels);
|
||||
|
||||
sampleRate = (int)inFile->getSampleRate();
|
||||
channels = (int)inFile->getNumChannels();
|
||||
pSoundTouch->setSampleRate(sampleRate);
|
||||
pSoundTouch->setChannels(channels);
|
||||
soundTouch.setTempoChange(params.tempoDelta);
|
||||
soundTouch.setPitchSemiTones(params.pitchDelta);
|
||||
soundTouch.setRateChange(params.rateDelta);
|
||||
|
||||
pSoundTouch->setTempoChange(params->tempoDelta);
|
||||
pSoundTouch->setPitchSemiTones(params->pitchDelta);
|
||||
pSoundTouch->setRateChange(params->rateDelta);
|
||||
soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick);
|
||||
soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias));
|
||||
|
||||
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick);
|
||||
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !(params->noAntiAlias));
|
||||
|
||||
if (params->speech)
|
||||
if (params.speech)
|
||||
{
|
||||
// use settings for speech processing
|
||||
pSoundTouch->setSetting(SETTING_SEQUENCE_MS, 40);
|
||||
pSoundTouch->setSetting(SETTING_SEEKWINDOW_MS, 15);
|
||||
pSoundTouch->setSetting(SETTING_OVERLAP_MS, 8);
|
||||
soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
|
||||
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
|
||||
soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
|
||||
fprintf(stderr, "Tune processing parameters for speech processing.\n");
|
||||
}
|
||||
|
||||
// print processing information
|
||||
if (params->outFileName)
|
||||
if (!params.outFileName.empty())
|
||||
{
|
||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
|
||||
@ -149,9 +145,9 @@ static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunPar
|
||||
#endif
|
||||
// print processing information only if outFileName given i.e. some processing will happen
|
||||
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, " 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
|
||||
@ -165,30 +161,24 @@ static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunPar
|
||||
|
||||
|
||||
// Processes the sound
|
||||
static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile)
|
||||
static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile)
|
||||
{
|
||||
int nSamples;
|
||||
int nChannels;
|
||||
int buffSizeSamples;
|
||||
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
||||
int nSamples;
|
||||
|
||||
if ((inFile == nullptr) || (outFile == nullptr)) return; // nothing to do.
|
||||
|
||||
nChannels = (int)inFile->getNumChannels();
|
||||
const int nChannels = (int)inFile.getNumChannels();
|
||||
assert(nChannels > 0);
|
||||
buffSizeSamples = BUFF_SIZE / nChannels;
|
||||
const int buffSizeSamples = BUFF_SIZE / nChannels;
|
||||
|
||||
// Process samples read from the input file
|
||||
while (inFile->eof() == 0)
|
||||
while (inFile.eof() == 0)
|
||||
{
|
||||
int num;
|
||||
|
||||
// Read a chunk of samples from the input file
|
||||
num = inFile->read(sampleBuffer, BUFF_SIZE);
|
||||
nSamples = num / (int)inFile->getNumChannels();
|
||||
const int num = inFile.read(sampleBuffer, BUFF_SIZE);
|
||||
int nSamples = num / (int)inFile.getNumChannels();
|
||||
|
||||
// Feed the samples into SoundTouch processor
|
||||
pSoundTouch->putSamples(sampleBuffer, nSamples);
|
||||
soundTouch.putSamples(sampleBuffer, nSamples);
|
||||
|
||||
// Read ready samples from SoundTouch processor & write them output file.
|
||||
// NOTES:
|
||||
@ -200,57 +190,53 @@ static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outF
|
||||
// outputs samples.
|
||||
do
|
||||
{
|
||||
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
||||
outFile->write(sampleBuffer, nSamples * nChannels);
|
||||
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
|
||||
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||
} while (nSamples != 0);
|
||||
}
|
||||
|
||||
// Now the input file is processed, yet 'flush' few last samples that are
|
||||
// hiding in the SoundTouch's internal processing pipeline.
|
||||
pSoundTouch->flush();
|
||||
soundTouch.flush();
|
||||
do
|
||||
{
|
||||
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
||||
outFile->write(sampleBuffer, nSamples * nChannels);
|
||||
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
|
||||
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||
} while (nSamples != 0);
|
||||
}
|
||||
|
||||
|
||||
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
|
||||
static void detectBPM(WavInFile *inFile, RunParameters *params)
|
||||
static void detectBPM(WavInFile& inFile, RunParameters& params)
|
||||
{
|
||||
float bpmValue;
|
||||
int nChannels;
|
||||
BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate());
|
||||
BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate());
|
||||
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
||||
|
||||
// detect bpm rate
|
||||
fprintf(stderr, "Detecting BPM rate...");
|
||||
fflush(stderr);
|
||||
|
||||
nChannels = (int)inFile->getNumChannels();
|
||||
const int nChannels = (int)inFile.getNumChannels();
|
||||
int readSize = BUFF_SIZE - BUFF_SIZE % nChannels; // round read size down to multiple of num.channels
|
||||
|
||||
// Process the 'inFile' in small blocks, repeat until whole file has
|
||||
// been processed
|
||||
while (inFile->eof() == 0)
|
||||
while (inFile.eof() == 0)
|
||||
{
|
||||
int num, samples;
|
||||
|
||||
// Read sample data from input file
|
||||
num = inFile->read(sampleBuffer, readSize);
|
||||
const int num = inFile.read(sampleBuffer, readSize);
|
||||
|
||||
// Enter the new samples to the bpm analyzer class
|
||||
samples = num / nChannels;
|
||||
const int samples = num / nChannels;
|
||||
bpm.inputSamples(sampleBuffer, samples);
|
||||
}
|
||||
|
||||
// Now the whole song data has been analyzed. Read the resulting bpm.
|
||||
bpmValue = bpm.getBpm();
|
||||
const float bpmValue = bpm.getBpm();
|
||||
fprintf(stderr, "Done!\n");
|
||||
|
||||
// rewind the file after bpm detection
|
||||
inFile->rewind();
|
||||
inFile.rewind();
|
||||
|
||||
if (bpmValue > 0)
|
||||
{
|
||||
@ -262,61 +248,64 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
|
||||
return;
|
||||
}
|
||||
|
||||
if (params->goalBPM > 0)
|
||||
if (params.goalBPM > 0)
|
||||
{
|
||||
// adjust tempo to given bpm
|
||||
params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f;
|
||||
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM);
|
||||
params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f;
|
||||
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params.goalBPM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(const int nParams, const char * const paramStr[])
|
||||
void ss_main(RunParameters& params)
|
||||
{
|
||||
WavInFile *inFile;
|
||||
WavOutFile *outFile;
|
||||
RunParameters *params;
|
||||
unique_ptr<WavInFile> inFile;
|
||||
unique_ptr<WavOutFile> outFile;
|
||||
SoundTouch soundTouch;
|
||||
|
||||
fprintf(stderr, _helloText, SoundTouch::getVersionString());
|
||||
|
||||
try
|
||||
{
|
||||
// Parse command line parameters
|
||||
params = new RunParameters(nParams, paramStr);
|
||||
fprintf(stderr, _helloText, soundTouch.getVersionString());
|
||||
|
||||
// Open input & output files
|
||||
openFiles(&inFile, &outFile, params);
|
||||
openFiles(inFile, outFile, params);
|
||||
|
||||
if (params->detectBPM == true)
|
||||
if (params.detectBPM == true)
|
||||
{
|
||||
// detect sound BPM (and adjust processing parameters
|
||||
// accordingly if necessary)
|
||||
detectBPM(inFile, params);
|
||||
detectBPM(*inFile, params);
|
||||
}
|
||||
|
||||
// Setup the 'SoundTouch' object for processing the sound
|
||||
setup(&soundTouch, inFile, params);
|
||||
setup(soundTouch, *inFile, params);
|
||||
|
||||
// clock_t cs = clock(); // for benchmarking processing duration
|
||||
// Process the sound
|
||||
process(&soundTouch, inFile, outFile);
|
||||
if (inFile && outFile)
|
||||
{
|
||||
process(soundTouch, *inFile, *outFile);
|
||||
}
|
||||
// clock_t ce = clock(); // for benchmarking processing duration
|
||||
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
|
||||
|
||||
// Close WAV file handles & dispose of the objects
|
||||
delete inFile;
|
||||
delete outFile;
|
||||
delete params;
|
||||
|
||||
fprintf(stderr, "Done!\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
int wmain(int argc, const wchar_t* args[])
|
||||
#else
|
||||
int main(int argc, const char* args[])
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
soundstretch::RunParameters params(argc, args);
|
||||
soundstretch::ss_main(params);
|
||||
}
|
||||
catch (const runtime_error& e)
|
||||
{
|
||||
// An exception occurred during processing, display an error message
|
||||
fprintf(stderr, "%s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -28,25 +28,25 @@
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@ -134,10 +134,7 @@
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||
@ -183,9 +180,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||
@ -234,9 +229,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||
@ -284,9 +277,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||
<GenerateMapFile>true</GenerateMapFile>
|
||||
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||
@ -327,6 +318,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="RunParameters.h" />
|
||||
<ClInclude Include="SS_CharTypes.h" />
|
||||
<ClInclude Include="WavFile.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -27,25 +27,25 @@
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@ -16,9 +16,10 @@
|
||||
#include "../../SoundStretch/WavFile.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace soundstretch;
|
||||
|
||||
// DllTest main
|
||||
int main(int argc, char *argv[])
|
||||
int wmain(int argc, const wchar_t *argv[])
|
||||
{
|
||||
// Check program arguments
|
||||
if (argc < 4)
|
||||
@ -27,22 +28,22 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *inFileName = argv[1];
|
||||
const char *outFileName = argv[2];
|
||||
string str_sampleType = argv[3];
|
||||
wstring inFileName = argv[1];
|
||||
wstring outFileName = argv[2];
|
||||
wstring str_sampleType = argv[3];
|
||||
|
||||
bool floatSample;
|
||||
if (str_sampleType.compare("float") == 0)
|
||||
if (str_sampleType == L"float")
|
||||
{
|
||||
floatSample = true;
|
||||
}
|
||||
else if (str_sampleType.compare("short") == 0)
|
||||
else if (str_sampleType == L"short")
|
||||
{
|
||||
floatSample = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Missing or invalid sampletype '" << str_sampleType << "'. Expected either short or float" << endl;
|
||||
cerr << "Missing or invalid sampletype. Expected either short or float" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -69,12 +69,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "Comments", "SoundTouch Library licensed for 3rd party applications subject to LGPL license v2.1. Visit http://www.surina.net/soundtouch for more information about the SoundTouch library."
|
||||
VALUE "FileDescription", "SoundTouch Dynamic Link Library"
|
||||
VALUE "FileVersion", "2.3.2.0"
|
||||
VALUE "FileVersion", "2.3.3.0"
|
||||
VALUE "InternalName", "SoundTouch"
|
||||
VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2023"
|
||||
VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2024"
|
||||
VALUE "OriginalFilename", "SoundTouch.dll"
|
||||
VALUE "ProductName", " SoundTouch Dynamic Link Library"
|
||||
VALUE "ProductVersion", "2.3.2.0"
|
||||
VALUE "ProductVersion", "2.3.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@ -27,22 +27,22 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user