23 |
#ifndef __LS_GIG_SYNTHESIZER_H__ |
#ifndef __LS_GIG_SYNTHESIZER_H__ |
24 |
#define __LS_GIG_SYNTHESIZER_H__ |
#define __LS_GIG_SYNTHESIZER_H__ |
25 |
|
|
26 |
|
#include "../../common/global.h" |
27 |
#include "../../common/RTMath.h" |
#include "../../common/RTMath.h" |
28 |
#include "../common/Resampler.h" |
#include "../common/Resampler.h" |
29 |
#include "../common/BiquadFilter.h" |
#include "../common/BiquadFilter.h" |
30 |
#include "Filter.h" |
#include "Filter.h" |
31 |
#include "Voice.h" |
#include "Voice.h" |
32 |
|
|
33 |
#define SYNTHESIS_MODE_SET_CONSTPITCH(iMode,bVal) if (bVal) iMode |= 0x01; else iMode &= 0xfe /* (un)set mode bit 0 */ |
#define SYNTHESIS_MODE_SET_CONSTPITCH(iMode,bVal) if (bVal) iMode |= 0x01; else iMode &= ~0x01 /* (un)set mode bit 0 */ |
34 |
#define SYNTHESIS_MODE_SET_LOOP(iMode,bVal) if (bVal) iMode |= 0x02; else iMode &= 0xfd /* (un)set mode bit 1 */ |
#define SYNTHESIS_MODE_SET_LOOP(iMode,bVal) if (bVal) iMode |= 0x02; else iMode &= ~0x02 /* (un)set mode bit 1 */ |
35 |
#define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal) if (bVal) iMode |= 0x04; else iMode &= 0xfb /* (un)set mode bit 2 */ |
#define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal) if (bVal) iMode |= 0x04; else iMode &= ~0x04 /* (un)set mode bit 2 */ |
36 |
#define SYNTHESIS_MODE_SET_FILTER(iMode,bVal) if (bVal) iMode |= 0x08; else iMode &= 0xf7 /* (un)set mode bit 3 */ |
#define SYNTHESIS_MODE_SET_FILTER(iMode,bVal) if (bVal) iMode |= 0x08; else iMode &= ~0x08 /* (un)set mode bit 3 */ |
37 |
#define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal) if (bVal) iMode |= 0x10; else iMode &= 0xef /* (un)set mode bit 4 */ |
#define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal) if (bVal) iMode |= 0x10; else iMode &= ~0x10 /* (un)set mode bit 4 */ |
38 |
#define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal) if (bVal) iMode |= 0x20; else iMode &= 0xdf /* (un)set mode bit 5 */ |
#define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal) if (bVal) iMode |= 0x20; else iMode &= ~0x20 /* (un)set mode bit 5 */ |
39 |
|
#define SYNTHESIS_MODE_SET_PROFILING(iMode,bVal) if (bVal) iMode |= 0x40; else iMode &= ~0x40 /* (un)set mode bit 6 */ |
40 |
|
|
41 |
#define SYNTHESIS_MODE_GET_CONSTPITCH(iMode) iMode & 0x01 |
#define SYNTHESIS_MODE_GET_CONSTPITCH(iMode) iMode & 0x01 |
42 |
#define SYNTHESIS_MODE_GET_LOOP(iMode) iMode & 0x02 |
#define SYNTHESIS_MODE_GET_LOOP(iMode) iMode & 0x02 |
54 |
|
|
55 |
namespace LinuxSampler { namespace gig { |
namespace LinuxSampler { namespace gig { |
56 |
|
|
57 |
typedef void SynthesizeFragment_Fn(VOICE&, uint, sample_t*, int); |
typedef void SynthesizeFragment_Fn(VOICE&, uint, sample_t*, uint); |
58 |
|
|
59 |
void* GetSynthesisFunction(const int SynthesisMode); |
void* GetSynthesisFunction(const int SynthesisMode); |
60 |
|
void RunSynthesisFunction(const int SynthesisMode, VOICE& voice, uint Samples, sample_t* pSrc, uint Skip); |
61 |
|
|
62 |
enum channels_t { |
enum channels_t { |
63 |
MONO, |
MONO, |
68 |
class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> { |
class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> { |
69 |
public: |
public: |
70 |
template<typename VOICE_T> |
template<typename VOICE_T> |
71 |
inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, int& i) { |
inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) { |
72 |
if (IMPLEMENTATION == ASM_X86_MMX_SSE) { |
if (IMPLEMENTATION == ASM_X86_MMX_SSE) { |
73 |
float fPos = (float) Voice.Pos; |
float fPos = (float) Voice.Pos; |
74 |
SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount, |
SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount, |
79 |
(void *)&fPos, |
(void *)&fPos, |
80 |
Voice.PitchBase, |
Voice.PitchBase, |
81 |
Voice.PitchBend); |
Voice.PitchBend); |
82 |
|
#if ARCH_X86 |
83 |
if (INTERPOLATE) EMMS; |
if (INTERPOLATE) EMMS; |
84 |
|
#endif |
85 |
Voice.Pos = (double) fPos; |
Voice.Pos = (double) fPos; |
86 |
} else { |
} else { |
87 |
SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount, |
SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount, |
98 |
//protected: |
//protected: |
99 |
|
|
100 |
template<typename VOICE_T> |
template<typename VOICE_T> |
101 |
inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, int& i, uint& LoopPlayCount, uint LoopStart, uint LoopEnd, uint LoopSize, uint& LoopCyclesLeft, void* Pos, float& PitchBase, float& PitchBend) { |
inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint& i, uint& LoopPlayCount, uint LoopStart, uint LoopEnd, uint LoopSize, uint& LoopCyclesLeft, void* Pos, float& PitchBase, float& PitchBend) { |
102 |
const float loopEnd = Float(LoopEnd); |
const float loopEnd = Float(LoopEnd); |
103 |
const float PBbyPB = Mul(PitchBase, PitchBend); |
const float PBbyPB = Mul(PitchBase, PitchBend); |
104 |
const float f_LoopStart = Float(LoopStart); |
const float f_LoopStart = Float(LoopStart); |
108 |
// render loop (loop count limited) |
// render loop (loop count limited) |
109 |
while (i < Samples && LoopCyclesLeft) { |
while (i < Samples && LoopCyclesLeft) { |
110 |
if (CONSTPITCH) { |
if (CONSTPITCH) { |
111 |
const int processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd,Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up |
const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd,Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up |
112 |
while (i < processEnd) Synthesize(Voice, Pos, pSrc, i); |
while (i < processEnd) Synthesize(Voice, Pos, pSrc, i); |
113 |
} |
} |
114 |
else Synthesize(Voice, Pos, pSrc, i); |
else Synthesize(Voice, Pos, pSrc, i); |
120 |
else { // render loop (endless loop) |
else { // render loop (endless loop) |
121 |
while (i < Samples) { |
while (i < Samples) { |
122 |
if (CONSTPITCH) { |
if (CONSTPITCH) { |
123 |
const int processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd, Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up |
const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd, Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up |
124 |
while (i < processEnd) Synthesize(Voice, Pos, pSrc, i); |
while (i < processEnd) Synthesize(Voice, Pos, pSrc, i); |
125 |
} |
} |
126 |
else Synthesize(Voice, Pos, pSrc, i); |
else Synthesize(Voice, Pos, pSrc, i); |
134 |
} |
} |
135 |
|
|
136 |
template<typename VOICE_T> |
template<typename VOICE_T> |
137 |
inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, int& i) { |
inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i) { |
138 |
Synthesize(pSrc, Pos, |
Synthesize(pSrc, Pos, |
139 |
Voice.pEngine->pSynthesisParameters[Event::destination_vco][i], |
Voice.pEngine->pSynthesisParameters[Event::destination_vco][i], |
140 |
Voice.pEngine->pOutputLeft, |
Voice.pEngine->pOutputLeft, |
153 |
switch (IMPLEMENTATION) { |
switch (IMPLEMENTATION) { |
154 |
// pure C++ implementation (thus platform independent) |
// pure C++ implementation (thus platform independent) |
155 |
case CPP: { |
case CPP: { |
156 |
return int((LoopEnd - *((double *)Pos)) / Pitch); |
return uint((LoopEnd - *((double *)Pos)) / Pitch); |
157 |
} |
} |
158 |
|
#if ARCH_X86 |
159 |
case ASM_X86_MMX_SSE: { |
case ASM_X86_MMX_SSE: { |
160 |
int result; |
int result; |
161 |
__asm__ __volatile__ ( |
__asm__ __volatile__ ( |
170 |
); |
); |
171 |
return result; |
return result; |
172 |
} |
} |
173 |
|
#endif // ARCH_X86 |
174 |
} |
} |
175 |
} |
} |
176 |
|
|
183 |
*Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart; |
*Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart; |
184 |
return 1; |
return 1; |
185 |
} |
} |
186 |
|
#if ARCH_X86 |
187 |
case ASM_X86_MMX_SSE: { |
case ASM_X86_MMX_SSE: { |
188 |
int result; |
int result = 0; |
189 |
__asm__ __volatile__ ( |
__asm__ __volatile__ ( |
190 |
"movss (%2), %%xmm0 # load LoopEnd\n\t" |
"movss (%2), %%xmm0 # load LoopEnd\n\t" |
191 |
"movss (%1), %%xmm1 # load Pos\n\t" |
"movss (%1), %%xmm1 # load Pos\n\t" |
192 |
"comiss %%xmm0, %%xmm1 # LoopEnd <> Pos\n\t" |
"comiss %%xmm0, %%xmm1 # LoopEnd <> Pos\n\t" |
|
"movl $0,%%eax # result = 0\n\t" |
|
193 |
"jb 1f # jump if no work needs to be done\n\t" |
"jb 1f # jump if no work needs to be done\n\t" |
194 |
"movss (%3), %%xmm2 # load LoopSize\n\t" |
"movss (%3), %%xmm2 # load LoopSize\n\t" |
195 |
"subss %%xmm0, %%xmm1 # Pos - LoopEnd\n\t" |
"subss %%xmm0, %%xmm1 # Pos - LoopEnd\n\t" |
204 |
//done with fmodf |
//done with fmodf |
205 |
"addss %%xmm0, %%xmm3 # add LoopStart\n\t" |
"addss %%xmm0, %%xmm3 # add LoopStart\n\t" |
206 |
"movss %%xmm3, (%1) # update Pos\n\t" |
"movss %%xmm3, (%1) # update Pos\n\t" |
207 |
"movl $1,%%eax # result = 1\n\t" |
"movl $1, (%0) # result = 1\n\t" |
208 |
".balign 16 \n\t" |
".balign 16 \n\t" |
209 |
"1:\n\t" |
"1:\n\t" |
210 |
: "=a" (result) /* %0 */ |
:: "r" (&result), /* %0 */ |
211 |
: "r" (vPos), /* %1 */ |
"r" (vPos), /* %1 */ |
212 |
"r" (&LoopEnd), /* %2 */ |
"r" (&LoopEnd), /* %2 */ |
213 |
"r" (&LoopSize), /* %3 */ |
"r" (&LoopSize), /* %3 */ |
214 |
"r" (&LoopStart) /* %4 */ |
"r" (&LoopStart) /* %4 */ |
215 |
); |
); |
216 |
return result; |
return result; |
217 |
} |
} |
218 |
|
#endif // ARCH_X86 |
219 |
} |
} |
220 |
} |
} |
221 |
|
|
222 |
inline static void Synthesize(sample_t* pSrc, void* Pos, float& Pitch, float* pOutL, float* pOutR, int& i, float* Volume, float* PanL, float* PanR, Filter& FilterL, Filter& FilterR, biquad_param_t& bqBase, biquad_param_t& bqMain) { |
inline static void Synthesize(sample_t* pSrc, void* Pos, float& Pitch, float* pOutL, float* pOutR, uint& i, float* Volume, float* PanL, float* PanR, Filter& FilterL, Filter& FilterR, biquad_param_t& bqBase, biquad_param_t& bqMain) { |
223 |
switch (IMPLEMENTATION) { |
switch (IMPLEMENTATION) { |
224 |
// pure C++ implementation (thus platform independent) |
// pure C++ implementation (thus platform independent) |
225 |
case CPP: { |
case CPP: { |
246 |
} |
} |
247 |
break; |
break; |
248 |
} |
} |
249 |
|
#if ARCH_X86 |
250 |
// Assembly optimization using the MMX & SSE(1) instruction set (thus only for x86) |
// Assembly optimization using the MMX & SSE(1) instruction set (thus only for x86) |
251 |
case ASM_X86_MMX_SSE: { |
case ASM_X86_MMX_SSE: { |
252 |
const int ii = i & 0xfffffffc; |
const int ii = i & 0xfffffffc; |
332 |
"r" (&pOutR[ii]) /* %1 - must be 16 byte aligned ! */ |
"r" (&pOutR[ii]) /* %1 - must be 16 byte aligned ! */ |
333 |
); |
); |
334 |
} |
} |
335 |
|
#endif // ARCH_X86 |
336 |
} |
} |
337 |
} |
} |
338 |
}; |
}; |