1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
/*
* MixerInterface.h
* ----------------
* Purpose: The basic mixer interface and main mixer loop, completely agnostic of the actual sample input / output formats.
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#pragma once
#include "openmpt/all/BuildSettings.hpp"
#include "Snd_defs.h"
#include "ModChannel.h"
OPENMPT_NAMESPACE_BEGIN
class CResampler;
//////////////////////////////////////////////////////////////////////////
// Sample conversion traits
template<int channelsOut, int channelsIn, typename out, typename in>
struct MixerTraits
{
static constexpr int numChannelsIn = channelsIn; // Number of channels in sample
static constexpr int numChannelsOut = channelsOut; // Number of mixer output channels
using output_t = out; // Output buffer sample type
using input_t = in; // Input buffer sample type
using outbuf_t = out[channelsOut]; // Output buffer sampling point type
// To perform sample conversion, add a function with the following signature to your derived classes:
// static MPT_CONSTEXPRINLINE output_t Convert(const input_t x)
};
//////////////////////////////////////////////////////////////////////////
// Interpolation templates
template<class Traits>
struct NoInterpolation
{
ModChannel &channel;
MPT_FORCEINLINE NoInterpolation(ModChannel &c, const CResampler &, unsigned int)
: channel{c}
{
// Adding 0.5 to the sample position before the interpolation loop starts
// effectively gives us nearest-neighbour with rounding instead of truncation.
// This gives us more consistent behaviour between forward and reverse playing of a sample.
c.position += SamplePosition::Ratio(1, 2);
}
MPT_FORCEINLINE ~NoInterpolation()
{
channel.position -= SamplePosition::Ratio(1, 2);
}
MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32)
{
static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
for(int i = 0; i < Traits::numChannelsIn; i++)
{
outSample[i] = Traits::Convert(inBuffer[i]);
}
}
};
// Other interpolation algorithms depend on the input format type (integer / float) and can thus be found in FloatMixer.h and IntMixer.h
//////////////////////////////////////////////////////////////////////////
// Main sample render loop template
// Template parameters:
// Traits: A class derived from MixerTraits that defines the number of channels, sample buffer types, etc..
// InterpolationFunc: Functor for reading the sample data and doing the SRC
// FilterFunc: Functor for applying the resonant filter
// MixFunc: Functor for mixing the computed sample data into the output buffer
template<class Traits, class InterpolationFunc, class FilterFunc, class MixFunc>
inline void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Traits::output_t * MPT_RESTRICT outBuffer, unsigned int numSamples)
{
ModChannel &c = chn;
const typename Traits::input_t * MPT_RESTRICT inSample = static_cast<const typename Traits::input_t *>(c.pCurrentSample);
InterpolationFunc interpolate{c, resampler, numSamples};
FilterFunc filter{c};
MixFunc mix{c};
unsigned int samples = numSamples;
SamplePosition smpPos = c.position; // Fixed-point sample position
const SamplePosition increment = c.increment; // Fixed-point sample increment
while(samples--)
{
typename Traits::outbuf_t outSample;
interpolate(outSample, inSample + smpPos.GetInt() * Traits::numChannelsIn, smpPos.GetFract());
filter(outSample, c);
mix(outSample, c, outBuffer);
outBuffer += Traits::numChannelsOut;
smpPos += increment;
}
c.position = smpPos;
}
// Type of the SampleLoop function above
using MixFuncInterface = void (*)(ModChannel &, const CResampler &, mixsample_t *, unsigned int);
OPENMPT_NAMESPACE_END
|