/[svn]/linuxsampler/trunk/src/engines/gig/Synthesizer.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/Synthesizer.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 411 - (hide annotations) (download) (as text)
Sat Feb 26 02:01:14 2005 UTC (19 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 20580 byte(s)
* design change: using now one sampler engine instance and one disk thread
  instance for all sampler channels that are connected to the same audio
  output device (and are using the same engine type of course)
* added EngineFactory / EngineChannelFactory to remove the annoying build
  dependencies e.g. of the lscpserver to the actual sampler engine
  implementations
* bumped version to 0.3.0 (current CVS state is still quite broken,
  previous, stable CVS version was tagged as "v0_2_0" and is also available
  as source tarball)

1 schoenebeck 320 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 411 * Copyright (C) 2005 Christian Schoenebeck *
7 schoenebeck 320 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #ifndef __LS_GIG_SYNTHESIZER_H__
25     #define __LS_GIG_SYNTHESIZER_H__
26    
27 schoenebeck 328 #include "../../common/global.h"
28 schoenebeck 320 #include "../../common/RTMath.h"
29     #include "../common/Resampler.h"
30     #include "../common/BiquadFilter.h"
31     #include "Filter.h"
32     #include "Voice.h"
33    
34 senkov 332 #define SYNTHESIS_MODE_SET_CONSTPITCH(iMode,bVal) if (bVal) iMode |= 0x01; else iMode &= ~0x01 /* (un)set mode bit 0 */
35     #define SYNTHESIS_MODE_SET_LOOP(iMode,bVal) if (bVal) iMode |= 0x02; else iMode &= ~0x02 /* (un)set mode bit 1 */
36     #define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal) if (bVal) iMode |= 0x04; else iMode &= ~0x04 /* (un)set mode bit 2 */
37     #define SYNTHESIS_MODE_SET_FILTER(iMode,bVal) if (bVal) iMode |= 0x08; else iMode &= ~0x08 /* (un)set mode bit 3 */
38     #define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal) if (bVal) iMode |= 0x10; else iMode &= ~0x10 /* (un)set mode bit 4 */
39     #define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal) if (bVal) iMode |= 0x20; else iMode &= ~0x20 /* (un)set mode bit 5 */
40 senkov 325 #define SYNTHESIS_MODE_SET_PROFILING(iMode,bVal) if (bVal) iMode |= 0x40; else iMode &= ~0x40 /* (un)set mode bit 6 */
41 schoenebeck 320
42     #define SYNTHESIS_MODE_GET_CONSTPITCH(iMode) iMode & 0x01
43     #define SYNTHESIS_MODE_GET_LOOP(iMode) iMode & 0x02
44     #define SYNTHESIS_MODE_GET_INTERPOLATE(iMode) iMode & 0x04
45     #define SYNTHESIS_MODE_GET_FILTER(iMode) iMode & 0x08
46     #define SYNTHESIS_MODE_GET_CHANNELS(iMode) iMode & 0x10
47     #define SYNTHESIS_MODE_GET_IMPLEMENTATION(iMode) iMode & 0x20
48    
49     // that's usually gig::Voice of course, but we make it a macro so we can
50     // include this code for our synthesis benchmark which uses fake data
51     // structures
52     #ifndef VOICE
53     # define VOICE Voice
54     #endif // VOICE
55    
56     namespace LinuxSampler { namespace gig {
57    
58 senkov 325 typedef void SynthesizeFragment_Fn(VOICE&, uint, sample_t*, uint);
59 schoenebeck 320
60     void* GetSynthesisFunction(const int SynthesisMode);
61 senkov 325 void RunSynthesisFunction(const int SynthesisMode, VOICE& voice, uint Samples, sample_t* pSrc, uint Skip);
62 schoenebeck 320
63     enum channels_t {
64     MONO,
65     STEREO
66     };
67    
68     template<implementation_t IMPLEMENTATION, channels_t CHANNELS, bool USEFILTER, bool INTERPOLATE, bool DOLOOP, bool CONSTPITCH>
69     class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> {
70     public:
71     template<typename VOICE_T>
72 senkov 325 inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) {
73 schoenebeck 320 if (IMPLEMENTATION == ASM_X86_MMX_SSE) {
74     float fPos = (float) Voice.Pos;
75     SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
76     Voice.pSample->LoopStart,
77     Voice.pSample->LoopEnd,
78     Voice.pSample->LoopSize,
79     Voice.LoopCyclesLeft,
80     (void *)&fPos,
81     Voice.PitchBase,
82     Voice.PitchBend);
83 schoenebeck 361 #if ARCH_X86
84 schoenebeck 320 if (INTERPOLATE) EMMS;
85 schoenebeck 361 #endif
86 schoenebeck 320 Voice.Pos = (double) fPos;
87     } else {
88     SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
89     Voice.pSample->LoopStart,
90     Voice.pSample->LoopEnd,
91     Voice.pSample->LoopSize,
92     Voice.LoopCyclesLeft,
93     (void *)&Voice.Pos,
94     Voice.PitchBase,
95     Voice.PitchBend);
96     }
97     }
98    
99     //protected:
100    
101     template<typename VOICE_T>
102 senkov 325 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) {
103 schoenebeck 320 const float loopEnd = Float(LoopEnd);
104     const float PBbyPB = Mul(PitchBase, PitchBend);
105     const float f_LoopStart = Float(LoopStart);
106     const float f_LoopSize = Float(LoopSize);
107     if (DOLOOP) {
108     if (LoopPlayCount) {
109     // render loop (loop count limited)
110     while (i < Samples && LoopCyclesLeft) {
111     if (CONSTPITCH) {
112 senkov 325 const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd,Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up
113 schoenebeck 320 while (i < processEnd) Synthesize(Voice, Pos, pSrc, i);
114     }
115     else Synthesize(Voice, Pos, pSrc, i);
116     if (WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos)) LoopCyclesLeft--;
117     }
118     // render on without loop
119     while (i < Samples) Synthesize(Voice, Pos, pSrc, i);
120     }
121     else { // render loop (endless loop)
122     while (i < Samples) {
123     if (CONSTPITCH) {
124 senkov 325 const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd, Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up
125 schoenebeck 320 while (i < processEnd) Synthesize(Voice, Pos, pSrc, i);
126     }
127     else Synthesize(Voice, Pos, pSrc, i);
128     WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);
129     }
130     }
131     }
132     else { // no looping
133     while (i < Samples) { Synthesize(Voice, Pos, pSrc, i);}
134     }
135     }
136    
137     template<typename VOICE_T>
138 senkov 325 inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i) {
139 schoenebeck 320 Synthesize(pSrc, Pos,
140     Voice.pEngine->pSynthesisParameters[Event::destination_vco][i],
141 schoenebeck 411 Voice.pEngineChannel->pOutputLeft,
142     Voice.pEngineChannel->pOutputRight,
143 schoenebeck 320 i,
144     Voice.pEngine->pSynthesisParameters[Event::destination_vca],
145     &Voice.PanLeft,
146     &Voice.PanRight,
147     Voice.FilterLeft,
148     Voice.FilterRight,
149     Voice.pEngine->pBasicFilterParameters[i],
150     Voice.pEngine->pMainFilterParameters[i]);
151     }
152    
153     inline static int DiffToLoopEnd(const float& LoopEnd, const void* Pos, const float& Pitch) {
154     switch (IMPLEMENTATION) {
155     // pure C++ implementation (thus platform independent)
156     case CPP: {
157 senkov 325 return uint((LoopEnd - *((double *)Pos)) / Pitch);
158 schoenebeck 320 }
159 schoenebeck 328 #if ARCH_X86
160 schoenebeck 320 case ASM_X86_MMX_SSE: {
161     int result;
162     __asm__ __volatile__ (
163     "movss (%1), %%xmm0 #read loopend\n\t"
164     "subss (%2), %%xmm0 #sub pos\n\t"
165     "divss (%3), %%xmm0 #div by pitch\n\t"
166     "cvtss2si %%xmm0, %0 #convert to int\n\t"
167     : "=r" (result) /* %0 */
168     : "r" (&LoopEnd), /* %1 */
169     "r" (Pos), /* %2 */
170     "r" (&Pitch) /* %3 */
171     );
172     return result;
173     }
174 schoenebeck 328 #endif // ARCH_X86
175 schoenebeck 320 }
176     }
177    
178     inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {
179     switch (IMPLEMENTATION) {
180     // pure C++ implementation (thus platform independent)
181     case CPP: {
182     double * Pos = (double *)vPos;
183     if (*Pos < LoopEnd) return 0;
184     *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;
185     return 1;
186     }
187 schoenebeck 328 #if ARCH_X86
188 schoenebeck 320 case ASM_X86_MMX_SSE: {
189 senkov 336 int result = 0;
190 schoenebeck 320 __asm__ __volatile__ (
191     "movss (%2), %%xmm0 # load LoopEnd\n\t"
192     "movss (%1), %%xmm1 # load Pos\n\t"
193     "comiss %%xmm0, %%xmm1 # LoopEnd <> Pos\n\t"
194     "jb 1f # jump if no work needs to be done\n\t"
195     "movss (%3), %%xmm2 # load LoopSize\n\t"
196     "subss %%xmm0, %%xmm1 # Pos - LoopEnd\n\t"
197     //now the fmodf
198     "movss %%xmm1, %%xmm3 # xmm3 = (Pos - LoopEnd)\n\t"
199     "divss %%xmm2, %%xmm1 # (Pos - LoopEnd) / LoopSize\n\t"
200     "cvttss2si %%xmm1, %%eax # convert to int\n\t"
201     "cvtsi2ss %%eax, %%xmm1 # convert back to float\n\t"
202     "movss (%4), %%xmm0 # load LoopStart\n\t"
203     "mulss %%xmm2, %%xmm1 # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"
204     "subss %%xmm1, %%xmm3 # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"
205     //done with fmodf
206     "addss %%xmm0, %%xmm3 # add LoopStart\n\t"
207     "movss %%xmm3, (%1) # update Pos\n\t"
208 senkov 336 "movl $1, (%0) # result = 1\n\t"
209 schoenebeck 320 ".balign 16 \n\t"
210     "1:\n\t"
211 senkov 336 :: "r" (&result), /* %0 */
212     "r" (vPos), /* %1 */
213 schoenebeck 320 "r" (&LoopEnd), /* %2 */
214     "r" (&LoopSize), /* %3 */
215     "r" (&LoopStart) /* %4 */
216     );
217     return result;
218     }
219 schoenebeck 328 #endif // ARCH_X86
220 schoenebeck 320 }
221     }
222    
223 senkov 325 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) {
224 schoenebeck 320 switch (IMPLEMENTATION) {
225     // pure C++ implementation (thus platform independent)
226     case CPP: {
227     switch (CHANNELS) {
228     case MONO: {
229     float samplePoint = GetNextSampleMonoCPP(pSrc, (double *)Pos, Pitch);
230     if (USEFILTER) samplePoint = FilterL.Apply(&bqBase, &bqMain, samplePoint);
231     pOutL[i] += samplePoint * Volume[i] * *PanL;
232     pOutR[i] += samplePoint * Volume[i] * *PanR;
233     i++;
234     break;
235     }
236     case STEREO: {
237     stereo_sample_t samplePoint = GetNextSampleStereoCPP(pSrc, (double *)Pos, Pitch);
238     if (USEFILTER) {
239     samplePoint.left = FilterL.Apply(&bqBase, &bqMain, samplePoint.left);
240     samplePoint.right = FilterR.Apply(&bqBase, &bqMain, samplePoint.right);
241     }
242     pOutL[i] += samplePoint.left * Volume[i] * *PanL;
243     pOutR[i] += samplePoint.right * Volume[i] * *PanR;
244     i++;
245     break;
246     }
247     }
248     break;
249     }
250 schoenebeck 328 #if ARCH_X86
251 schoenebeck 320 // Assembly optimization using the MMX & SSE(1) instruction set (thus only for x86)
252     case ASM_X86_MMX_SSE: {
253     const int ii = i & 0xfffffffc;
254     i += 4;
255     switch (CHANNELS) {
256     case MONO: {
257     GetNext4SamplesMonoMMXSSE(pSrc, (float *)Pos, Pitch); // outputs samples in xmm2
258     if (USEFILTER) {
259     /* prepare filter input */
260     __asm__ __volatile__ (
261     "movaps %xmm2,%xmm0"
262     );
263     FilterL.Apply4StepsSSE(&bqBase, &bqMain); // xmm0 input, xmm7 output
264     __asm__ __volatile__ (
265     "movaps %xmm7,%xmm2 # mono filter result -> xmm2"
266     );
267     }
268     /* apply panorama and volume factors */
269     __asm__ __volatile__ (
270     "movss (%1),%%xmm0 # load pan left\n\t"
271     "movss (%2),%%xmm1 # load pan right\n\t"
272     "movaps (%0),%%xmm4 # load vca\n\t"
273     "shufps $0x00,%%xmm0,%%xmm0 # copy pan left to the other 3 cells\n\t"
274     "shufps $0x00,%%xmm1,%%xmm1 # copy pan right to the other 3 cells\n\t"
275     "mulps %%xmm2,%%xmm0 # left = sample * pan_left\n\t"
276     "mulps %%xmm2,%%xmm1 # right = sample * pan_right\n\t"
277     "mulps %%xmm4,%%xmm0 # left = vca * (sample * pan_left)\n\t"
278     "mulps %%xmm4,%%xmm1 # right = vca * (sample * pan_right)\n\t"
279     : /* no output */
280     : "r" (&Volume[ii]), /* %0 */
281     "r" (PanL), /* %1 */
282     "r" (PanR) /* %2 */
283     : "xmm0", /* holds final left sample (for the 4 samples) at the end */
284     "xmm1" /* holds final right sample (for the 4 samples) at the end */
285     );
286     break;
287     }
288     case STEREO: {
289     GetNext4SamplesStereoMMXSSE(pSrc, (float *)Pos, Pitch); // outputs samples in xmm2 (left channel) and xmm3 (right channel)
290     if (USEFILTER) {
291     __asm__ __volatile__ (
292     "movaps %xmm2,%xmm0 # prepare left channel for filter\n\t"
293     "movaps %xmm3,%xmm1 # save right channel not to get overwritten by filter algorithms\n\t"
294     );
295     FilterL.Apply4StepsSSE(&bqBase, &bqMain); // xmm0 input, xmm7 output
296     __asm__ __volatile__ (
297     "movaps %xmm1,%xmm0 # prepare right channel for filter\n\t"
298     "movaps %xmm7,%xmm1 # save filter output for left channel\n\t"
299     );
300     FilterR.Apply4StepsSSE(&bqBase, &bqMain); // xmm0 input, xmm7 output
301     __asm__ __volatile__ (
302     "movaps %xmm1,%xmm2 # result left channel -> xmm2\n\t"
303     "movaps %xmm7,%xmm3 # result right channel -> xmm3\n\t"
304     );
305     }
306     /* apply panorama and volume factors */
307     __asm__ __volatile__ (
308     "movss (%1),%%xmm0 # load pan left\n\t"
309     "movss (%2),%%xmm1 # load pan right\n\t"
310     "movaps (%0),%%xmm4 # load vca\n\t"
311     "shufps $0x00,%%xmm0,%%xmm0 # copy pan left to the other 3 cells\n\t"
312     "shufps $0x00,%%xmm1,%%xmm1 # copy pan right to the other 3 cells\n\t"
313     "mulps %%xmm2,%%xmm0 # left = sample_left * pan_left\n\t"
314     "mulps %%xmm3,%%xmm1 # right = sample_right * pan_right\n\t"
315     "mulps %%xmm4,%%xmm0 # left = vca * (sample_left * pan_left)\n\t"
316     "mulps %%xmm4,%%xmm1 # right = vca * (sample_right * pan_right)\n\t"
317     : /* no output */
318     : "r" (&Volume[ii]), /* %0 */
319     "r" (PanL), /* %1 */
320     "r" (PanR) /* %2 */
321     );
322     break;
323     }
324     }
325     /* mix the 4 samples to the output channels */
326     __asm__ __volatile__ (
327     "addps (%0),%%xmm0 # mix calculated sample(s) to output left\n\t"
328     "movaps %%xmm0,(%0) # output to left channel\n\t"
329     "addps (%1),%%xmm1 # mix calculated sample(s) to output right\n\t"
330     "movaps %%xmm1,(%1) # output to right channel\n\t"
331     : /* no output */
332     : "r" (&pOutL[ii]), /* %0 - must be 16 byte aligned ! */
333     "r" (&pOutR[ii]) /* %1 - must be 16 byte aligned ! */
334     );
335     }
336 schoenebeck 328 #endif // ARCH_X86
337 schoenebeck 320 }
338     }
339     };
340    
341     }} // namespace LinuxSampler::gig
342    
343     #endif // __LS_GIG_SYNTHESIZER_H__

  ViewVC Help
Powered by ViewVC