add required deps for rpcli
This commit is contained in:
4
zefie_wtvp_minisrv/ra_win/build.cmd
Normal file
4
zefie_wtvp_minisrv/ra_win/build.cmd
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo OFF
|
||||||
|
cl rpcli.cpp /O2 /MT /Fe:rpcli.exe
|
||||||
|
del rpcli.obj prct3260.thl
|
||||||
|
|
||||||
BIN
zefie_wtvp_minisrv/ra_win/prob3260.dll
Normal file
BIN
zefie_wtvp_minisrv/ra_win/prob3260.dll
Normal file
Binary file not shown.
5
zefie_wtvp_minisrv/ra_win/readme.txt
Normal file
5
zefie_wtvp_minisrv/ra_win/readme.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
RealProducer G2 (or later) must be installed for this tool to work.
|
||||||
|
The free installer is included at rprodg261.exe.
|
||||||
|
|
||||||
|
Once installed, simply click cancel until you get to the RealProducer window, then close it.
|
||||||
|
The CLI app should then work.
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
// Build (MSVC example):
|
// Build (MSVC example):
|
||||||
// cl rpcli.cpp /O2 /MT /Fe:rpcli.exe
|
// cl rpcli.cpp /O2 /MT /Fe:rpcli.exe
|
||||||
//
|
//
|
||||||
// You must also #import the RealProducer control type library (prct3260.ocx).
|
// This tool imports and loads the RealProducer control type library (prct3260.ocx)
|
||||||
// Adjust the path below to wherever the control is registered/installed.
|
// from the same folder as the executable at runtime (no global COM registration required).
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
#error rpcli.cpp uses C++ COM features (#import, __uuidof). Compile with MSVC C++.
|
#error rpcli.cpp uses C++ COM features (#import, __uuidof). Compile with MSVC C++.
|
||||||
@@ -25,8 +25,14 @@
|
|||||||
|
|
||||||
static void die(const char *msg);
|
static void die(const char *msg);
|
||||||
static void cleanup_temp_input(void);
|
static void cleanup_temp_input(void);
|
||||||
|
static HRESULT create_local_producer_control(IProducerControl **ctlOut, char *loadedPath, size_t loadedPathSize);
|
||||||
|
static void unload_local_ocx(void);
|
||||||
|
|
||||||
static char g_temp_input_path[MAX_PATH] = {0};
|
static char g_temp_input_path[MAX_PATH] = {0};
|
||||||
|
static char g_temp_resample_path[MAX_PATH] = {0};
|
||||||
|
static HMODULE g_local_ocx_module = NULL;
|
||||||
|
|
||||||
|
typedef HRESULT (STDAPICALLTYPE *DllGetClassObjectFn)(REFCLSID rclsid, REFIID riid, LPVOID *ppv);
|
||||||
|
|
||||||
static BSTR ansi_to_bstr(const char *s) {
|
static BSTR ansi_to_bstr(const char *s) {
|
||||||
int wlen;
|
int wlen;
|
||||||
@@ -112,6 +118,99 @@ static void cleanup_temp_input(void) {
|
|||||||
DeleteFileA(g_temp_input_path);
|
DeleteFileA(g_temp_input_path);
|
||||||
g_temp_input_path[0] = '\0';
|
g_temp_input_path[0] = '\0';
|
||||||
}
|
}
|
||||||
|
if (g_temp_resample_path[0]) {
|
||||||
|
DeleteFileA(g_temp_resample_path);
|
||||||
|
g_temp_resample_path[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unload_local_ocx(void) {
|
||||||
|
if (g_local_ocx_module) {
|
||||||
|
FreeLibrary(g_local_ocx_module);
|
||||||
|
g_local_ocx_module = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT create_local_producer_control(IProducerControl **ctlOut, char *loadedPath, size_t loadedPathSize) {
|
||||||
|
char ocxPath[MAX_PATH];
|
||||||
|
DWORD pathLen;
|
||||||
|
HMODULE module = NULL;
|
||||||
|
DllGetClassObjectFn dllGetClassObject;
|
||||||
|
IClassFactory *factory = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (!ctlOut) {
|
||||||
|
return E_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ctlOut = NULL;
|
||||||
|
if (loadedPath && loadedPathSize > 0) {
|
||||||
|
loadedPath[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
pathLen = GetModuleFileNameA(NULL, ocxPath, (DWORD)sizeof(ocxPath));
|
||||||
|
if (pathLen == 0 || pathLen >= sizeof(ocxPath)) {
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char *lastSep = strrchr(ocxPath, '\\');
|
||||||
|
if (!lastSep) lastSep = strrchr(ocxPath, '/');
|
||||||
|
if (lastSep) {
|
||||||
|
strcpy(lastSep + 1, "prct3260.ocx");
|
||||||
|
} else {
|
||||||
|
strcpy(ocxPath, "prct3260.ocx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Set CWD to the exe folder so the patched OCX's "DT_Codecs=.\" and
|
||||||
|
"DT_Plugins=.\" paths resolve to the directory containing the OCX/DLLs. */
|
||||||
|
{
|
||||||
|
char exeDir[MAX_PATH];
|
||||||
|
char *lastSep2;
|
||||||
|
strncpy(exeDir, ocxPath, sizeof(exeDir) - 1);
|
||||||
|
exeDir[sizeof(exeDir) - 1] = '\0';
|
||||||
|
lastSep2 = strrchr(exeDir, '\\');
|
||||||
|
if (lastSep2) {
|
||||||
|
*lastSep2 = '\0';
|
||||||
|
SetCurrentDirectoryA(exeDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetFileAttributesA(ocxPath) == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
module = LoadLibraryExA(ocxPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||||
|
if (!module) {
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
dllGetClassObject = (DllGetClassObjectFn)GetProcAddress(module, "DllGetClassObject");
|
||||||
|
if (!dllGetClassObject) {
|
||||||
|
FreeLibrary(module);
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = dllGetClassObject(__uuidof(ProducerControl), __uuidof(IClassFactory), (void **)&factory);
|
||||||
|
if (FAILED(hr) || !factory) {
|
||||||
|
FreeLibrary(module);
|
||||||
|
return FAILED(hr) ? hr : E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = factory->CreateInstance(NULL, __uuidof(IProducerControl), (void **)ctlOut);
|
||||||
|
factory->Release();
|
||||||
|
|
||||||
|
if (FAILED(hr) || !*ctlOut) {
|
||||||
|
FreeLibrary(module);
|
||||||
|
return FAILED(hr) ? hr : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_local_ocx_module = module;
|
||||||
|
if (loadedPath && loadedPathSize > 0) {
|
||||||
|
strncpy(loadedPath, ocxPath, loadedPathSize - 1);
|
||||||
|
loadedPath[loadedPathSize - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *path_ext(const char *path) {
|
static const char *path_ext(const char *path) {
|
||||||
@@ -289,6 +388,21 @@ static int make_temp_wav_path(char *pathBuf, size_t pathBufSize) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int resolve_full_path(const char *path, char *pathBuf, size_t pathBufSize) {
|
||||||
|
DWORD written;
|
||||||
|
|
||||||
|
if (!path || !*path || !pathBuf || pathBufSize < MAX_PATH) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
written = GetFullPathNameA(path, (DWORD)pathBufSize, pathBuf, NULL);
|
||||||
|
if (written == 0 || written >= pathBufSize) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_mpeg_audio_to_wav(const char *inputPath,
|
static int decode_mpeg_audio_to_wav(const char *inputPath,
|
||||||
char *outputPath,
|
char *outputPath,
|
||||||
size_t outputPathSize,
|
size_t outputPathSize,
|
||||||
@@ -302,26 +416,45 @@ static int decode_mpeg_audio_to_wav(const char *inputPath,
|
|||||||
unsigned dataBytes = 0;
|
unsigned dataBytes = 0;
|
||||||
unsigned long long gainSamples = 0;
|
unsigned long long gainSamples = 0;
|
||||||
unsigned long long gainChanged = 0;
|
unsigned long long gainChanged = 0;
|
||||||
|
unsigned long long loopCount = 0;
|
||||||
|
unsigned long long decodeCalls = 0;
|
||||||
|
unsigned long long zeroFrameBytes = 0;
|
||||||
|
unsigned long long zeroSampleFrames = 0;
|
||||||
|
unsigned long long writtenFrames = 0;
|
||||||
int sampleRate = 0;
|
int sampleRate = 0;
|
||||||
int channels = 0;
|
int channels = 0;
|
||||||
int haveAudio = 0;
|
int haveAudio = 0;
|
||||||
|
|
||||||
if (!make_temp_wav_path(outputPath, outputPathSize)) {
|
if (!make_temp_wav_path(outputPath, outputPathSize)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: failed to create temp wav path (outputPathSize=%llu)\n",
|
||||||
|
(unsigned long long)outputPathSize);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputData = read_entire_file(inputPath, &inputSize);
|
inputData = read_entire_file(inputPath, &inputSize);
|
||||||
if (!inputData) {
|
if (!inputData) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: failed to read input file '%s'\n",
|
||||||
|
inputPath ? inputPath : "(null)");
|
||||||
|
DeleteFileA(outputPath);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = fopen(outputPath, "wb");
|
out = fopen(outputPath, "wb");
|
||||||
if (!out) {
|
if (!out) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: failed to open temp wav for write '%s'\n",
|
||||||
|
outputPath);
|
||||||
free(inputData);
|
free(inputData);
|
||||||
|
DeleteFileA(outputPath);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(wavHeader, 1, sizeof(wavHeader), out) != sizeof(wavHeader)) {
|
if (fwrite(wavHeader, 1, sizeof(wavHeader), out) != sizeof(wavHeader)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: failed to write placeholder wav header '%s'\n",
|
||||||
|
outputPath);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
free(inputData);
|
free(inputData);
|
||||||
@@ -335,17 +468,30 @@ static int decode_mpeg_audio_to_wav(const char *inputPath,
|
|||||||
int samples = mp3dec_decode_frame(&dec, inputData + pos, (int)(inputSize - pos), pcm, &info);
|
int samples = mp3dec_decode_frame(&dec, inputData + pos, (int)(inputSize - pos), pcm, &info);
|
||||||
int totalSamples;
|
int totalSamples;
|
||||||
|
|
||||||
|
++loopCount;
|
||||||
|
++decodeCalls;
|
||||||
|
|
||||||
if (info.frame_bytes <= 0) {
|
if (info.frame_bytes <= 0) {
|
||||||
|
++zeroFrameBytes;
|
||||||
++pos;
|
++pos;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += (size_t)info.frame_bytes;
|
pos += (size_t)info.frame_bytes;
|
||||||
if (samples <= 0) {
|
if (samples <= 0) {
|
||||||
|
++zeroSampleFrames;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.channels <= 0) {
|
if (info.channels <= 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: invalid channels=%d at loop=%llu pos=%llu frame_bytes=%d samples=%d hz=%d\n",
|
||||||
|
info.channels,
|
||||||
|
loopCount,
|
||||||
|
(unsigned long long)pos,
|
||||||
|
info.frame_bytes,
|
||||||
|
samples,
|
||||||
|
info.hz);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
free(inputData);
|
free(inputData);
|
||||||
@@ -359,6 +505,14 @@ static int decode_mpeg_audio_to_wav(const char *inputPath,
|
|||||||
channels = info.channels;
|
channels = info.channels;
|
||||||
haveAudio = 1;
|
haveAudio = 1;
|
||||||
} else if (sampleRate != info.hz || channels != info.channels) {
|
} else if (sampleRate != info.hz || channels != info.channels) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: stream format changed at loop=%llu pos=%llu from %dHz/%dch to %dHz/%dch\n",
|
||||||
|
loopCount,
|
||||||
|
(unsigned long long)pos,
|
||||||
|
sampleRate,
|
||||||
|
channels,
|
||||||
|
info.hz,
|
||||||
|
info.channels);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
free(inputData);
|
free(inputData);
|
||||||
@@ -379,17 +533,24 @@ static int decode_mpeg_audio_to_wav(const char *inputPath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(pcm, sizeof(mp3d_sample_t), (size_t)totalSamples, out) != (size_t)totalSamples) {
|
if (fwrite(pcm, sizeof(mp3d_sample_t), (size_t)totalSamples, out) != (size_t)totalSamples) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: fwrite failed at frame=%llu totalSamples=%d\n",
|
||||||
|
writtenFrames,
|
||||||
|
totalSamples);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
free(inputData);
|
free(inputData);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
++writtenFrames;
|
||||||
dataBytes += (unsigned)(totalSamples * sizeof(mp3d_sample_t));
|
dataBytes += (unsigned)(totalSamples * sizeof(mp3d_sample_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(inputData);
|
free(inputData);
|
||||||
|
|
||||||
if (!haveAudio) {
|
if (!haveAudio) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"decode: failed - no decodable audio frames found\n");
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -397,6 +558,7 @@ static int decode_mpeg_audio_to_wav(const char *inputPath,
|
|||||||
|
|
||||||
fill_wav_header(wavHeader, dataBytes, sampleRate, channels, 16);
|
fill_wav_header(wavHeader, dataBytes, sampleRate, channels, 16);
|
||||||
if (fseek(out, 0, SEEK_SET) != 0 || fwrite(wavHeader, 1, sizeof(wavHeader), out) != sizeof(wavHeader)) {
|
if (fseek(out, 0, SEEK_SET) != 0 || fwrite(wavHeader, 1, sizeof(wavHeader), out) != sizeof(wavHeader)) {
|
||||||
|
fprintf(stderr, "decode: failed writing wav header\n");
|
||||||
fclose(out);
|
fclose(out);
|
||||||
DeleteFileA(outputPath);
|
DeleteFileA(outputPath);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -544,6 +706,165 @@ static int rewrite_wav_with_gain(const char *inputPath,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nearest_supported_rate(int rate) {
|
||||||
|
static const int rates[] = {11025, 16000, 22050, 32000, 44100};
|
||||||
|
int i;
|
||||||
|
int best = rates[0];
|
||||||
|
int bestDiff = abs(rate - rates[0]);
|
||||||
|
for (i = 1; i < (int)(sizeof(rates) / sizeof(rates[0])); ++i) {
|
||||||
|
int diff = abs(rate - rates[i]);
|
||||||
|
if (diff < bestDiff) {
|
||||||
|
bestDiff = diff;
|
||||||
|
best = rates[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *resample_pcm16(const unsigned char *inputBytes,
|
||||||
|
unsigned inputSamples,
|
||||||
|
int channels,
|
||||||
|
int inRate,
|
||||||
|
int outRate,
|
||||||
|
unsigned *outputSamplesOut) {
|
||||||
|
unsigned inputFrames;
|
||||||
|
unsigned outputFrames;
|
||||||
|
unsigned totalOut;
|
||||||
|
short *output;
|
||||||
|
unsigned f;
|
||||||
|
|
||||||
|
if (!inputBytes || inputSamples == 0 || channels <= 0 || inRate <= 0 || outRate <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputFrames = inputSamples / (unsigned)channels;
|
||||||
|
outputFrames = (unsigned)((unsigned long long)inputFrames * (unsigned)outRate / (unsigned)inRate);
|
||||||
|
if (outputFrames == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalOut = outputFrames * (unsigned)channels;
|
||||||
|
output = (short *)malloc(totalOut * sizeof(short));
|
||||||
|
if (!output) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (f = 0; f < outputFrames; ++f) {
|
||||||
|
double pos = (double)f * inRate / outRate;
|
||||||
|
unsigned p0 = (unsigned)pos;
|
||||||
|
unsigned p1 = p0 + 1;
|
||||||
|
double frac = pos - (double)p0;
|
||||||
|
int c;
|
||||||
|
if (p1 >= inputFrames) {
|
||||||
|
p1 = inputFrames - 1;
|
||||||
|
}
|
||||||
|
for (c = 0; c < channels; ++c) {
|
||||||
|
unsigned i0 = (p0 * (unsigned)channels + (unsigned)c) * 2u;
|
||||||
|
unsigned i1 = (p1 * (unsigned)channels + (unsigned)c) * 2u;
|
||||||
|
short s0 = (short)((unsigned short)inputBytes[i0] | ((unsigned short)inputBytes[i0 + 1] << 8));
|
||||||
|
short s1 = (short)((unsigned short)inputBytes[i1] | ((unsigned short)inputBytes[i1 + 1] << 8));
|
||||||
|
double sv = (double)s0 + ((double)s1 - (double)s0) * frac;
|
||||||
|
short out;
|
||||||
|
if (sv > 32767.0) out = 32767;
|
||||||
|
else if (sv < -32768.0) out = -32768;
|
||||||
|
else out = (short)(sv >= 0.0 ? sv + 0.5 : sv - 0.5);
|
||||||
|
output[f * (unsigned)channels + (unsigned)c] = out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*outputSamplesOut = totalOut;
|
||||||
|
return (unsigned char *)output;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resample_wav_if_needed(const char *inputPath,
|
||||||
|
char *outputPath,
|
||||||
|
size_t outputPathSize) {
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
size_t fmtOffset;
|
||||||
|
unsigned fmtSize;
|
||||||
|
size_t dataOffset;
|
||||||
|
unsigned dataSize;
|
||||||
|
unsigned short formatTag;
|
||||||
|
unsigned short channels;
|
||||||
|
unsigned sampleRate;
|
||||||
|
unsigned short bitsPerSample;
|
||||||
|
int targetRate;
|
||||||
|
unsigned outputSamples = 0;
|
||||||
|
unsigned char *resampled = NULL;
|
||||||
|
FILE *out = NULL;
|
||||||
|
unsigned char header[44] = {0};
|
||||||
|
|
||||||
|
if (!outputPath || outputPathSize == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPath[0] = '\0';
|
||||||
|
data = read_entire_file(inputPath, &size);
|
||||||
|
if (!data) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!find_wav_data_chunk(data, size, &fmtOffset, &fmtSize, &dataOffset, &dataSize) || fmtSize < 16) {
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTag = (unsigned short)(data[fmtOffset] | (data[fmtOffset + 1] << 8));
|
||||||
|
channels = (unsigned short)(data[fmtOffset + 2] | (data[fmtOffset + 3] << 8));
|
||||||
|
sampleRate = (unsigned)data[fmtOffset + 4] | ((unsigned)data[fmtOffset + 5] << 8) |
|
||||||
|
((unsigned)data[fmtOffset + 6] << 16) | ((unsigned)data[fmtOffset + 7] << 24);
|
||||||
|
bitsPerSample = (unsigned short)(data[fmtOffset + 14] | (data[fmtOffset + 15] << 8));
|
||||||
|
|
||||||
|
if (formatTag != 1 || bitsPerSample != 16 || channels == 0) {
|
||||||
|
free(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetRate = nearest_supported_rate((int)sampleRate);
|
||||||
|
if (targetRate == (int)sampleRate) {
|
||||||
|
free(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "resampling: %u Hz -> %d Hz\n", sampleRate, targetRate);
|
||||||
|
|
||||||
|
resampled = resample_pcm16(data + dataOffset, dataSize / 2u,
|
||||||
|
(int)channels, (int)sampleRate, targetRate,
|
||||||
|
&outputSamples);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
if (!resampled) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!make_temp_wav_path(outputPath, outputPathSize)) {
|
||||||
|
free(resampled);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = fopen(outputPath, "wb");
|
||||||
|
if (!out) {
|
||||||
|
free(resampled);
|
||||||
|
outputPath[0] = '\0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_wav_header(header, outputSamples * 2u, targetRate, (int)channels, 16);
|
||||||
|
if (fwrite(header, 1, sizeof(header), out) != sizeof(header) ||
|
||||||
|
fwrite(resampled, 2u, (size_t)outputSamples, out) != (size_t)outputSamples) {
|
||||||
|
fclose(out);
|
||||||
|
DeleteFileA(outputPath);
|
||||||
|
free(resampled);
|
||||||
|
outputPath[0] = '\0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
free(resampled);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Map rating string to something we can store as a property
|
// Map rating string to something we can store as a property
|
||||||
static const char *rating_to_str(const char *r) {
|
static const char *rating_to_str(const char *r) {
|
||||||
if (_stricmp(r, "G") == 0) return "G";
|
if (_stricmp(r, "G") == 0) return "G";
|
||||||
@@ -1251,6 +1572,9 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
const char *infile = NULL;
|
const char *infile = NULL;
|
||||||
char outbuf[MAX_PATH] = {0};
|
char outbuf[MAX_PATH] = {0};
|
||||||
|
char infile_abs[MAX_PATH] = {0};
|
||||||
|
char outfile_abs[MAX_PATH] = {0};
|
||||||
|
char ocx_loaded_path[MAX_PATH] = {0};
|
||||||
const char *outfile = NULL;
|
const char *outfile = NULL;
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
@@ -1332,6 +1656,20 @@ int main(int argc, char **argv) {
|
|||||||
outfile = outbuf;
|
outfile = outbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (infile && !resolve_full_path(infile, infile_abs, sizeof(infile_abs))) {
|
||||||
|
die("failed to resolve full path for input file");
|
||||||
|
}
|
||||||
|
if (outfile && !resolve_full_path(outfile, outfile_abs, sizeof(outfile_abs))) {
|
||||||
|
die("failed to resolve full path for output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (infile) {
|
||||||
|
infile = infile_abs;
|
||||||
|
}
|
||||||
|
if (outfile) {
|
||||||
|
outfile = outfile_abs;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&id3_meta, 0, sizeof(id3_meta));
|
memset(&id3_meta, 0, sizeof(id3_meta));
|
||||||
if (use_id3 && !load_id3_metadata(infile, &id3_meta)) {
|
if (use_id3 && !load_id3_metadata(infile, &id3_meta)) {
|
||||||
fprintf(stderr, "warning: no usable ID3 metadata found in %s\n", infile);
|
fprintf(stderr, "warning: no usable ID3 metadata found in %s\n", infile);
|
||||||
@@ -1354,19 +1692,16 @@ int main(int argc, char **argv) {
|
|||||||
if (FAILED(hr)) die("CoInitialize failed");
|
if (FAILED(hr)) die("CoInitialize failed");
|
||||||
|
|
||||||
IProducerControl *ctl = NULL;
|
IProducerControl *ctl = NULL;
|
||||||
hr = CoCreateInstance(__uuidof(ProducerControl),
|
hr = create_local_producer_control(&ctl, ocx_loaded_path, sizeof(ocx_loaded_path));
|
||||||
NULL,
|
|
||||||
CLSCTX_INPROC_SERVER,
|
|
||||||
__uuidof(IProducerControl),
|
|
||||||
(void**)&ctl);
|
|
||||||
if (FAILED(hr) || !ctl) {
|
if (FAILED(hr) || !ctl) {
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("failed to create ProducerControl (is prct3260.ocx installed/registered?)");
|
die("failed to create ProducerControl from local prct3260.ocx in current folder");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_codec_list) {
|
if (do_codec_list) {
|
||||||
list_codecs(ctl);
|
list_codecs(ctl);
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1379,6 +1714,7 @@ int main(int argc, char **argv) {
|
|||||||
if (is_mpeg_audio_input(infile)) {
|
if (is_mpeg_audio_input(infile)) {
|
||||||
if (!decode_mpeg_audio_to_wav(infile, decoded_input, sizeof(decoded_input), gain_scale)) {
|
if (!decode_mpeg_audio_to_wav(infile, decoded_input, sizeof(decoded_input), gain_scale)) {
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("failed to decode mpeg audio input with minimp3");
|
die("failed to decode mpeg audio input with minimp3");
|
||||||
}
|
}
|
||||||
@@ -1387,6 +1723,7 @@ int main(int argc, char **argv) {
|
|||||||
} else if (use_gain && is_wav_input(infile)) {
|
} else if (use_gain && is_wav_input(infile)) {
|
||||||
if (!rewrite_wav_with_gain(infile, decoded_input, sizeof(decoded_input), gain_scale)) {
|
if (!rewrite_wav_with_gain(infile, decoded_input, sizeof(decoded_input), gain_scale)) {
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("failed to apply gain to wav input; only PCM 16-bit WAV is supported");
|
die("failed to apply gain to wav input; only PCM 16-bit WAV is supported");
|
||||||
}
|
}
|
||||||
@@ -1394,8 +1731,23 @@ int main(int argc, char **argv) {
|
|||||||
encoder_input = g_temp_input_path;
|
encoder_input = g_temp_input_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resample to nearest supported rate: 11025, 16000, 22050, 32000, 44100 (cap at 44100)
|
||||||
|
{
|
||||||
|
int rsResult = resample_wav_if_needed(encoder_input, g_temp_resample_path, sizeof(g_temp_resample_path));
|
||||||
|
if (rsResult < 0) {
|
||||||
|
fprintf(stderr, "warning: could not check sample rate of input; using as-is\n");
|
||||||
|
} else if (rsResult > 0) {
|
||||||
|
if (g_temp_input_path[0]) {
|
||||||
|
DeleteFileA(g_temp_input_path);
|
||||||
|
g_temp_input_path[0] = '\0';
|
||||||
|
}
|
||||||
|
encoder_input = g_temp_resample_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (codec_index >= 0 && !get_audio_codec_by_index(ctl, codec_index, &selected_codec)) {
|
if (codec_index >= 0 && !get_audio_codec_by_index(ctl, codec_index, &selected_codec)) {
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("invalid codec index");
|
die("invalid codec index");
|
||||||
}
|
}
|
||||||
@@ -1437,6 +1789,7 @@ int main(int argc, char **argv) {
|
|||||||
if (codec_index >= 0 && !apply_selected_audio_codec(ctl, parse_target(target_str), &selected_codec)) {
|
if (codec_index >= 0 && !apply_selected_audio_codec(ctl, parse_target(target_str), &selected_codec)) {
|
||||||
if (selected_codec.cookie) selected_codec.cookie->Release();
|
if (selected_codec.cookie) selected_codec.cookie->Release();
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("failed to apply selected codec");
|
die("failed to apply selected codec");
|
||||||
}
|
}
|
||||||
@@ -1449,6 +1802,7 @@ int main(int argc, char **argv) {
|
|||||||
hr = ctl->StartEncoding();
|
hr = ctl->StartEncoding();
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
die("StartEncoding failed");
|
die("StartEncoding failed");
|
||||||
}
|
}
|
||||||
@@ -1491,6 +1845,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (selected_codec.cookie) selected_codec.cookie->Release();
|
if (selected_codec.cookie) selected_codec.cookie->Release();
|
||||||
ctl->Release();
|
ctl->Release();
|
||||||
|
unload_local_ocx();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
cleanup_temp_input();
|
cleanup_temp_input();
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
BIN
zefie_wtvp_minisrv/ra_win/rprodg261.exe
Normal file
BIN
zefie_wtvp_minisrv/ra_win/rprodg261.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user