Windows: SoundStretch to accept wide-character command line attributes to support asian/non-latin files names.

This commit is contained in:
Olli Parviainen 2024-02-11 15:27:45 +02:00
parent 74514f5597
commit 375e6ccfe9
13 changed files with 485 additions and 488 deletions

View File

@ -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)

View File

@ -16,7 +16,7 @@
<body class="normal">
<hr>
<h1>SoundTouch audio processing library v2.3.2</h1>
<p class="normal">SoundTouch library Copyright &copy; Olli Parviainen 2001-2022</p>
<p class="normal">SoundTouch library Copyright &copy; 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>

View File

@ -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:

View File

@ -30,15 +30,18 @@
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <stdlib.h>
#include <cstdlib>
#include "RunParameters.h"
using namespace std;
namespace soundstretch
{
// Program usage instructions
static const char licenseText[] =
static const char licenseText[] =
" LICENSE:\n"
" ========\n"
" \n"
@ -61,12 +64,12 @@ static const char licenseText[] =
"This application is distributed with full source codes; however, if you\n"
"didn't receive them, please visit the author's homepage (see the link above).";
static const char whatText[] =
static const char whatText[] =
"This application processes WAV audio files by modifying the sound tempo,\n"
"pitch and playback rate properties independently from each other.\n"
"\n";
static const char usage[] =
static const char usage[] =
"Usage :\n"
" soundstretch infilename outfilename [switches]\n"
"\n"
@ -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);
}
}
}

View File

@ -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

View File

@ -42,17 +42,26 @@
#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 ";
static const char fmtStr[] = "fmt ";
static const char factStr[] = "fact";
static const char dataStr[] = "data";
@ -66,67 +75,67 @@ static const char dataStr[] = "data";
// while PowerPC of Mac's and many other RISC cpu's are big-endian.
#ifdef BYTE_ORDER
// In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN
// big-endian platform.
#define _BIG_ENDIAN_
#endif
// In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN
// big-endian platform.
#define _BIG_ENDIAN_
#endif
#endif
#ifdef _BIG_ENDIAN_
// big-endian CPU, swap bytes in 16 & 32 bit words
// big-endian CPU, swap bytes in 16 & 32 bit words
// helper-function to swap byte-order of 32bit integer
static inline int _swap32(int &dwData)
{
dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) |
((dwData << 24) & 0xFF000000);
return dwData;
}
// helper-function to swap byte-order of 32bit integer
static inline int _swap32(int& dwData)
{
dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) |
((dwData << 24) & 0xFF000000);
return dwData;
}
// helper-function to swap byte-order of 16bit integer
static inline short _swap16(short &wData)
// helper-function to swap byte-order of 16bit integer
static inline short _swap16(short& wData)
{
wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00);
return wData;
}
// helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(short* pData, int numWords)
{
int i;
for (i = 0; i < numWords; i++)
{
wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00);
return wData;
}
// helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(short *pData, int numWords)
{
int i;
for (i = 0; i < numWords; i ++)
{
pData[i] = _swap16(pData[i]);
}
pData[i] = _swap16(pData[i]);
}
}
#else // BIG_ENDIAN
// little-endian CPU, WAV file is ok as such
// little-endian CPU, WAV file is ok as such
// dummy helper-function
static inline int _swap32(int &dwData)
{
// do nothing
return dwData;
}
// dummy helper-function
static inline int _swap32(int& dwData)
{
// do nothing
return dwData;
}
// dummy helper-function
static inline short _swap16(short &wData)
{
// do nothing
return wData;
}
// dummy helper-function
static inline short _swap16(short& wData)
{
// do nothing
return wData;
}
// dummy helper-function
static inline void _swap16Buffer(short *, int)
{
// do nothing
}
// dummy helper-function
static inline void _swap16Buffer(short*, int)
{
// do nothing
}
#endif // BIG_ENDIAN
@ -151,7 +160,7 @@ WavFileBase::~WavFileBase()
/// Get pointer to conversion buffer of at min. given size
void *WavFileBase::getConvBuffer(int sizeBytes)
void* WavFileBase::getConvBuffer(int sizeBytes)
{
if (convBuffSize < sizeBytes)
{
@ -169,32 +178,26 @@ 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");
if (fptr == nullptr)
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();
}
WavInFile::WavInFile(FILE *file)
WavInFile::WavInFile(FILE* file)
{
// Try to open the file for reading
fptr = file;
if (!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();
@ -211,19 +214,17 @@ void WavInFile::init()
// Read the file headers
hdrsOk = readWavHeaders();
if (hdrsOk != 0)
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");
}
// sanity check for format parameters
if ((header.format.channel_number < 1) || (header.format.channel_number > 9) ||
(header.format.sample_rate < 4000) || (header.format.sample_rate > 192000) ||
if ((header.format.channel_number < 1) || (header.format.channel_number > 9) ||
(header.format.sample_rate < 4000) || (header.format.sample_rate > 192000) ||
(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.");
}
@ -260,7 +261,7 @@ int WavInFile::checkCharTags() const
}
int WavInFile::read(unsigned char *buffer, int maxElems)
int WavInFile::read(unsigned char* buffer, int maxElems)
{
int numBytes;
uint afterDataRead;
@ -274,7 +275,7 @@ int WavInFile::read(unsigned char *buffer, int maxElems)
numBytes = maxElems;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead;
@ -289,7 +290,7 @@ int WavInFile::read(unsigned char *buffer, int maxElems)
}
int WavInFile::read(short *buffer, int maxElems)
int WavInFile::read(short* buffer, int maxElems)
{
unsigned int afterDataRead;
int numBytes;
@ -298,53 +299,53 @@ int WavInFile::read(short *buffer, int maxElems)
assert(buffer);
switch (header.format.bits_per_sample)
{
case 8:
{
// 8 bit format
unsigned char *temp = (unsigned char*)getConvBuffer(maxElems);
int i;
case 8:
{
// 8 bit format
unsigned char* temp = (unsigned char*)getConvBuffer(maxElems);
int i;
numElems = read(temp, maxElems);
// convert from 8 to 16 bit
for (i = 0; i < numElems; i ++)
{
buffer[i] = (short)(((short)temp[i] - 128) * 256);
}
break;
numElems = read(temp, maxElems);
// convert from 8 to 16 bit
for (i = 0; i < numElems; i++)
{
buffer[i] = (short)(((short)temp[i] - 128) * 256);
}
break;
}
case 16:
{
// 16 bit format
assert(sizeof(short) == 2);
numBytes = maxElems * 2;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead;
assert(numBytes >= 0);
}
case 16:
{
// 16 bit format
numBytes = (int)fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
numElems = numBytes / 2;
assert(sizeof(short) == 2);
// 16bit samples, swap byte order if necessary
_swap16Buffer((short*)buffer, numElems);
break;
}
numBytes = maxElems * 2;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead;
assert(numBytes >= 0);
}
numBytes = (int)fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
numElems = numBytes / 2;
// 16bit samples, swap byte order if necessary
_swap16Buffer((short *)buffer, numElems);
break;
}
default:
{
stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample;
ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str());
}
default:
{
stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample;
ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str());
}
};
return numElems;
@ -353,7 +354,7 @@ int WavInFile::read(short *buffer, int maxElems)
/// Read data in float format. Notice that when reading in float format
/// 8/16/24/32 bit sample formats are supported
int WavInFile::read(float *buffer, int maxElems)
int WavInFile::read(float* buffer, int maxElems)
{
unsigned int afterDataRead;
int numBytes;
@ -374,7 +375,7 @@ int WavInFile::read(float *buffer, int maxElems)
numBytes = maxElems * bytesPerSample;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead;
@ -382,7 +383,7 @@ int WavInFile::read(float *buffer, int maxElems)
}
// read raw data into temporary buffer
char *temp = (char*)getConvBuffer(numBytes);
char* temp = (char*)getConvBuffer(numBytes);
numBytes = (int)fread(temp, 1, numBytes, fptr);
dataRead += numBytes;
@ -391,56 +392,56 @@ int WavInFile::read(float *buffer, int maxElems)
// swap byte ordert & convert to float, depending on sample format
switch (bytesPerSample)
{
case 1:
case 1:
{
unsigned char* temp2 = (unsigned char*)temp;
double conv = 1.0 / 128.0;
for (int i = 0; i < numElems; i++)
{
unsigned char *temp2 = (unsigned char*)temp;
double conv = 1.0 / 128.0;
for (int i = 0; i < numElems; i ++)
{
buffer[i] = (float)(temp2[i] * conv - 1.0);
}
break;
buffer[i] = (float)(temp2[i] * conv - 1.0);
}
break;
}
case 2:
case 2:
{
short* temp2 = (short*)temp;
double conv = 1.0 / 32768.0;
for (int i = 0; i < numElems; i++)
{
short *temp2 = (short*)temp;
double conv = 1.0 / 32768.0;
for (int i = 0; i < numElems; i ++)
{
short value = temp2[i];
buffer[i] = (float)(_swap16(value) * conv);
}
break;
short value = temp2[i];
buffer[i] = (float)(_swap16(value) * conv);
}
break;
}
case 3:
case 3:
{
char* temp2 = (char*)temp;
double conv = 1.0 / 8388608.0;
for (int i = 0; i < numElems; i++)
{
char *temp2 = (char *)temp;
double conv = 1.0 / 8388608.0;
for (int i = 0; i < numElems; i ++)
{
int value = *((int*)temp2);
value = _swap32(value) & 0x00ffffff; // take 24 bits
value |= (value & 0x00800000) ? 0xff000000 : 0; // extend minus sign bits
buffer[i] = (float)(value * conv);
temp2 += 3;
}
break;
int value = *((int*)temp2);
value = _swap32(value) & 0x00ffffff; // take 24 bits
value |= (value & 0x00800000) ? 0xff000000 : 0; // extend minus sign bits
buffer[i] = (float)(value * conv);
temp2 += 3;
}
break;
}
case 4:
case 4:
{
int* temp2 = (int*)temp;
double conv = 1.0 / 2147483648.0;
assert(sizeof(int) == 4);
for (int i = 0; i < numElems; i++)
{
int *temp2 = (int *)temp;
double conv = 1.0 / 2147483648.0;
assert(sizeof(int) == 4);
for (int i = 0; i < numElems; i ++)
{
int value = temp2[i];
buffer[i] = (float)(_swap32(value) * conv);
}
break;
int value = temp2[i];
buffer[i] = (float)(_swap32(value) * conv);
}
break;
}
}
return numElems;
@ -462,15 +463,15 @@ static int isAlpha(char c)
// test if all characters are between a white space ' ' and little 'z'
static int isAlphaStr(const char *str)
static int isAlphaStr(const char* str)
{
char c;
c = str[0];
while (c)
while (c)
{
if (isAlpha(c) == 0) return 0;
str ++;
str++;
c = str[0];
}
@ -483,7 +484,7 @@ int WavInFile::readRIFFBlock()
if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1;
// swap 32bit data byte order if necessary
_swap32((int &)header.riff.package_len);
_swap32((int&)header.riff.package_len);
// header.riff.riff_char should equal to 'RIFF');
if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;
@ -500,7 +501,7 @@ int WavInFile::readHeaderBlock()
string sLabel;
// lead label string
if (fread(label, 1, 4, fptr) !=4) return -1;
if (fread(label, 1, 4, fptr) != 4) return -1;
label[4] = 0;
if (isAlphaStr(label) == 0) return -1; // not a valid label
@ -536,12 +537,12 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap16((short &)header.format.fixed); // short int fixed;
_swap16((short &)header.format.channel_number); // short int channel_number;
_swap32((int &)header.format.sample_rate); // int sample_rate;
_swap32((int &)header.format.byte_rate); // int byte_rate;
_swap16((short &)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((short &)header.format.bits_per_sample); // short int bits_per_sample;
_swap16((short&)header.format.fixed); // short int fixed;
_swap16((short&)header.format.channel_number); // short int channel_number;
_swap32((int&)header.format.sample_rate); // int sample_rate;
_swap32((int&)header.format.byte_rate); // int byte_rate;
_swap16((short&)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((short&)header.format.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data
if (nDump > 0)
@ -581,7 +582,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap32((int &)header.fact.fact_sample_len); // int sample_length;
_swap32((int&)header.fact.fact_sample_len); // int sample_length;
// if fact_len is larger than expected, skip the extra data
if (nDump > 0)
@ -598,7 +599,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap32((int &)header.data.data_len);
_swap32((int&)header.data.data_len);
return 1;
}
@ -611,7 +612,7 @@ int WavInFile::readHeaderBlock()
// read length
if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
// scan through the block
for (i = 0; i < len; i ++)
for (i = 0; i < len; i++)
{
if (fread(&temp, 1, 1, fptr) != 1) return -1;
if (feof(fptr)) return -1; // unexpected eof
@ -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");
if (fptr == nullptr)
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);
@ -721,14 +718,13 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
}
WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
WavOutFile::WavOutFile(FILE* file, int sampleRate, int bits, int channels)
{
bytesWritten = 0;
fptr = file;
if (fptr == nullptr)
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);
@ -788,8 +784,8 @@ void WavOutFile::finishHeader()
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4;
header.data.data_len = bytesWritten;
header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample;
header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample;
writeHeader();
}
@ -801,18 +797,18 @@ void WavOutFile::writeHeader()
// swap byte order if necessary
hdrTemp = header;
_swap32((int &)hdrTemp.riff.package_len);
_swap32((int &)hdrTemp.format.format_len);
_swap16((short &)hdrTemp.format.fixed);
_swap16((short &)hdrTemp.format.channel_number);
_swap32((int &)hdrTemp.format.sample_rate);
_swap32((int &)hdrTemp.format.byte_rate);
_swap16((short &)hdrTemp.format.byte_per_sample);
_swap16((short &)hdrTemp.format.bits_per_sample);
_swap32((int &)hdrTemp.data.data_len);
_swap32((int &)hdrTemp.fact.fact_len);
_swap32((int &)hdrTemp.fact.fact_sample_len);
_swap32((int&)hdrTemp.riff.package_len);
_swap32((int&)hdrTemp.format.format_len);
_swap16((short&)hdrTemp.format.fixed);
_swap16((short&)hdrTemp.format.channel_number);
_swap32((int&)hdrTemp.format.sample_rate);
_swap32((int&)hdrTemp.format.byte_rate);
_swap16((short&)hdrTemp.format.byte_per_sample);
_swap16((short&)hdrTemp.format.bits_per_sample);
_swap32((int&)hdrTemp.data.data_len);
_swap32((int&)hdrTemp.fact.fact_len);
_swap32((int&)hdrTemp.fact.fact_sample_len);
// write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET);
res = (int)fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr);
@ -826,7 +822,7 @@ void WavOutFile::writeHeader()
}
void WavOutFile::write(const unsigned char *buffer, int numElems)
void WavOutFile::write(const unsigned char* buffer, int numElems)
{
int res;
@ -837,7 +833,7 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
assert(sizeof(char) == 1);
res = (int)fwrite(buffer, 1, numElems, fptr);
if (res != numElems)
if (res != numElems)
{
ST_THROW_RT_ERROR("Error while writing to a wav file.");
}
@ -846,7 +842,7 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
}
void WavOutFile::write(const short *buffer, int numElems)
void WavOutFile::write(const short* buffer, int numElems)
{
int res;
@ -855,47 +851,47 @@ void WavOutFile::write(const short *buffer, int numElems)
switch (header.format.bits_per_sample)
{
case 8:
case 8:
{
int i;
unsigned char* temp = (unsigned char*)getConvBuffer(numElems);
// convert from 16bit format to 8bit format
for (i = 0; i < numElems; i++)
{
int i;
unsigned char *temp = (unsigned char *)getConvBuffer(numElems);
// convert from 16bit format to 8bit format
for (i = 0; i < numElems; i ++)
{
temp[i] = (unsigned char)(buffer[i] / 256 + 128);
}
// write in 8bit format
write(temp, numElems);
break;
temp[i] = (unsigned char)(buffer[i] / 256 + 128);
}
// write in 8bit format
write(temp, numElems);
break;
}
case 16:
case 16:
{
// 16bit format
// use temp buffer to swap byte order if necessary
short* pTemp = (short*)getConvBuffer(numElems * sizeof(short));
memcpy(pTemp, buffer, (size_t)numElems * 2L);
_swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr);
if (res != numElems)
{
// 16bit format
// use temp buffer to swap byte order if necessary
short *pTemp = (short *)getConvBuffer(numElems * sizeof(short));
memcpy(pTemp, buffer, numElems * 2);
_swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr);
if (res != numElems)
{
ST_THROW_RT_ERROR("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
break;
ST_THROW_RT_ERROR("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
break;
}
default:
{
stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample;
ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str());
}
default:
{
stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample;
ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str());
}
}
}
@ -903,10 +899,10 @@ void WavOutFile::write(const short *buffer, int numElems)
/// Convert from float to integer and saturate
inline int saturate(float fvalue, float minval, float maxval)
{
if (fvalue > maxval)
if (fvalue > maxval)
{
fvalue = maxval;
}
}
else if (fvalue < minval)
{
fvalue = minval;
@ -915,7 +911,7 @@ inline int saturate(float fvalue, float minval, float maxval)
}
void WavOutFile::write(const float *buffer, int numElems)
void WavOutFile::write(const float* buffer, int numElems)
{
int numBytes;
int bytesPerSample;
@ -924,63 +920,65 @@ void WavOutFile::write(const float *buffer, int numElems)
bytesPerSample = header.format.bits_per_sample / 8;
numBytes = numElems * bytesPerSample;
void *temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
void* temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
switch (bytesPerSample)
{
case 1:
case 1:
{
unsigned char* temp2 = (unsigned char*)temp;
for (int i = 0; i < numElems; i++)
{
unsigned char *temp2 = (unsigned char *)temp;
for (int i = 0; i < numElems; i ++)
{
temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);
}
break;
temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);
}
break;
}
case 2:
case 2:
{
short* temp2 = (short*)temp;
for (int i = 0; i < numElems; i++)
{
short *temp2 = (short *)temp;
for (int i = 0; i < numElems; i ++)
{
short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);
temp2[i] = _swap16(value);
}
break;
short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);
temp2[i] = _swap16(value);
}
break;
}
case 3:
case 3:
{
char* temp2 = (char*)temp;
for (int i = 0; i < numElems; i++)
{
char *temp2 = (char *)temp;
for (int i = 0; i < numElems; i ++)
{
int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);
*((int*)temp2) = _swap32(value);
temp2 += 3;
}
break;
int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);
*((int*)temp2) = _swap32(value);
temp2 += 3;
}
break;
}
case 4:
case 4:
{
int* temp2 = (int*)temp;
for (int i = 0; i < numElems; i++)
{
int *temp2 = (int *)temp;
for (int i = 0; i < numElems; i ++)
{
int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);
temp2[i] = _swap32(value);
}
break;
int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);
temp2[i] = _swap32(value);
}
break;
}
default:
assert(false);
default:
assert(false);
}
int res = (int)fwrite(temp, 1, numBytes, fptr);
if (res != numBytes)
if (res != numBytes)
{
ST_THROW_RT_ERROR("Error while writing to a wav file.");
}
bytesWritten += numBytes;
}
}

View File

@ -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

View File

@ -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,22 +43,25 @@
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
#if _WIN32
#include <io.h>
#include <fcntl.h>
#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))
// 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) {}
#define SET_STREAM_TO_BIN_MODE(f) {}
#endif
static const char _helloText[] =
static const char _helloText[] =
"\n"
" SoundStretch v%s - Copyright (c) Olli Parviainen\n"
"=========================================================\n"
@ -68,90 +73,81 @@ 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");
#else
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined"
#endif
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined"
#endif
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
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:
@ -198,59 +188,55 @@ static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outF
// ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it
// outputs samples.
do
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();
do
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());
fprintf(stderr, _helloText, soundTouch.getVersionString());
try
// Open input & output files
openFiles(inFile, outFile, params);
if (params.detectBPM == true)
{
// Parse command line parameters
params = new RunParameters(nParams, paramStr);
// detect sound BPM (and adjust processing parameters
// accordingly if necessary)
detectBPM(*inFile, params);
}
// Open input & output files
openFiles(&inFile, &outFile, params);
// Setup the 'SoundTouch' object for processing the sound
setup(soundTouch, *inFile, params);
if (params->detectBPM == true)
{
// detect sound BPM (and adjust processing parameters
// accordingly if necessary)
detectBPM(inFile, params);
}
// Setup the 'SoundTouch' object for processing the sound
setup(&soundTouch, inFile, params);
// clock_t cs = clock(); // for benchmarking processing duration
// Process the sound
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");
}
catch (const runtime_error &e)
// clock_t cs = clock(); // for benchmarking processing duration
// Process the sound
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);
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;
}

View File

@ -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>

View File

@ -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">

View File

@ -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;
}

View File

@ -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"

View File

@ -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">