winamp/Src/Winamp/DecodeFile.cpp

203 lines
6.1 KiB
C++

/** (c) Nullsoft, Inc. C O N F I D E N T I A L
** Filename:
** Project:
** Description:
** Author: Ben Allison benski@nullsoft.com
** Created:
**/
#include "main.h"
#include <stddef.h>
#include "DecodeFile.h"
#include "ExtendedReader.h"
#include "OutputPluginAudioStream.h"
#include "ResamplingReader.h"
#include "CommonReader.h"
// "input" means input FROM the decoder, "output" means output TO the person using the ifc_audiostream
static bool RequiresResampling(const AudioParameters *input, size_t outputChannels, size_t outputBits, size_t outputSampleRate)
{
if (outputChannels != input->channels)
return true; // need to up or downmix
if (outputBits != input->bitsPerSample)
return true;
if (outputSampleRate != input->sampleRate)
return true;
return false;
}
static void SetResamplingParameters(const AudioParameters *input, size_t &outputChannels, size_t &outputBits, size_t &outputSampleRate)
{
// channels
if (!outputChannels)
outputChannels=input->channels;
else if ((input->flags & AUDIOPARAMETERS_MAXCHANNELS) && input->channels <= outputChannels)
outputChannels = input->channels;
// bits
if (!outputBits) outputBits = input->bitsPerSample;
// samplerate
if (!outputSampleRate)
outputSampleRate = input->sampleRate;
else if ((input->flags & AUDIOPARAMETERS_MAXSAMPLERATE) && input->sampleRate <= outputSampleRate)
outputSampleRate = input->sampleRate;
}
ifc_audiostream *DecodeFile::OpenAudio(const wchar_t *filename, AudioParameters *parameters)
{
// save some info
size_t outputChannels = parameters->channels;
size_t outputBits = parameters->bitsPerSample;
size_t outputSampleRate = parameters->sampleRate;
CommonReader *reader = MakeReader(filename, parameters, true);
if (!reader)
return 0;
// check if they've requested certain output parameters
if (outputChannels || outputBits || outputSampleRate)
{
SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
// check if we need any resampling/conversion
if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
{
Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
if (!resampler->OK())
{
parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
delete resampler;
return 0;
}
parameters->bitsPerSample = (uint32_t)outputBits;
parameters->channels = (uint32_t)outputChannels;
parameters->sampleRate = (uint32_t)outputSampleRate;
parameters->sizeBytes =(size_t)((double)parameters->sizeBytes * resampler->sizeFactor);
ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
return resampleReader;
}
}
return reader;
}
ifc_audiostream *DecodeFile::OpenAudioBackground(const wchar_t *filename, AudioParameters *parameters)
{
// save some info
size_t outputChannels = parameters->channels;
size_t outputBits = parameters->bitsPerSample;
size_t outputSampleRate = parameters->sampleRate;
CommonReader *reader = MakeReader(filename, parameters, false);
if (!reader)
return 0;
// check if they've requested certain output parameters
if (outputChannels || outputBits || outputSampleRate)
{
SetResamplingParameters(parameters, outputChannels, outputBits, outputSampleRate);
// check if we need any resampling/conversion
if (RequiresResampling(parameters, outputChannels, outputBits, outputSampleRate))
{
Resampler *resampler = new Resampler(parameters->bitsPerSample, parameters->channels, parameters->sampleRate,
outputBits, outputChannels, outputSampleRate, parameters->flags & AUDIOPARAMETERS_FLOAT);
if (!resampler->OK())
{
parameters->errorCode = API_DECODEFILE_BAD_RESAMPLE;
delete resampler;
delete reader;
return 0;
}
parameters->bitsPerSample = (uint32_t)outputBits;
parameters->channels = (uint32_t)outputChannels;
parameters->sampleRate = (uint32_t)outputSampleRate;
ResamplingReader *resampleReader = new ResamplingReader(resampler, reader, outputChannels * outputBits / 8);
return resampleReader;
}
}
return reader;
}
CommonReader *DecodeFile::MakeReader(const wchar_t *filename, AudioParameters *parameters, bool useUnagi)
{
In_Module *in;
int a = 0;
bool found = false;
while (a >= 0)
{
OpenFunc open = 0, openFloat=0;
OpenWFunc openW=0, openWFloat=0;
GetDataFunc getData = 0;
CloseFunc close = 0;
SetTimeFunc setTime = 0;
in = in_setmod_noplay(filename, &a);
if (!in) break;
if (a >= 0) a++;
found = true;
open = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open");
openFloat = (OpenFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_open_float");
openW = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW");
openWFloat = (OpenWFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_openW_float");
getData = (GetDataFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_getData");
close = (CloseFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_close");
setTime = (SetTimeFunc)GetProcAddress(in->hDllInstance, "winampGetExtendedRead_setTime"); //optional!
if ((open || openW) && getData && close)
{
ExtendedReader *reader = new ExtendedReader(open, openW, openFloat, openWFloat, getData, close, setTime);
if (reader->Open(filename, parameters))
return reader;
else
delete reader;
}
}
if (!found || !useUnagi)
{
parameters->errorCode = API_DECODEFILE_UNSUPPORTED;
}
else
{
OutputPluginAudioStream *reader = new OutputPluginAudioStream;
in = in_setmod_noplay(filename, 0);
if (reader->Open(in, filename, parameters))
return reader;
delete reader;
}
return 0;
}
void DecodeFile::CloseAudio(ifc_audiostream *audioStream)
{
CommonReader *reader = static_cast<CommonReader *>(audioStream);
delete reader;
//audioStream=0;
}
#define CBCLASS DecodeFile
START_DISPATCH;
CB(API_DECODEFILE_OPENAUDIO, OpenAudio)
CB(API_DECODEFILE_OPENAUDIO2, OpenAudioBackground)
VCB(API_DECODEFILE_CLOSEAUDIO, CloseAudio)
END_DISPATCH;