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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 424 by schoenebeck, Fri Mar 4 22:54:11 2005 UTC revision 738 by schoenebeck, Tue Aug 16 17:14:25 2005 UTC
# Line 31  Line 31 
31  #include "Filter.h"  #include "Filter.h"
32  #include "Voice.h"  #include "Voice.h"
33    
34  #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 */  #define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal)      if (bVal) iMode |= 0x01; else iMode &= ~0x01   /* (un)set mode bit 0 */
36  #define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal)      if (bVal) iMode |= 0x04; else iMode &= ~0x04   /* (un)set mode bit 2 */  #define SYNTHESIS_MODE_SET_FILTER(iMode,bVal)           if (bVal) iMode |= 0x02; else iMode &= ~0x02   /* (un)set mode bit 1 */
37  #define SYNTHESIS_MODE_SET_FILTER(iMode,bVal)           if (bVal) iMode |= 0x08; else iMode &= ~0x08   /* (un)set mode bit 3 */  #define SYNTHESIS_MODE_SET_LOOP(iMode,bVal)             if (bVal) iMode |= 0x04; else iMode &= ~0x04   /* (un)set mode bit 2 */
38  #define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal)         if (bVal) iMode |= 0x10; else iMode &= ~0x10   /* (un)set mode bit 4 */  #define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal)         if (bVal) iMode |= 0x08; else iMode &= ~0x08   /* (un)set mode bit 3 */
39  #define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal)   if (bVal) iMode |= 0x20; else iMode &= ~0x20   /* (un)set mode bit 5 */  #define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal)   if (bVal) iMode |= 0x10; else iMode &= ~0x10   /* (un)set mode bit 4 */
40  #define SYNTHESIS_MODE_SET_PROFILING(iMode,bVal)        if (bVal) iMode |= 0x40; else iMode &= ~0x40   /* (un)set mode bit 6 */  #define SYNTHESIS_MODE_SET_PROFILING(iMode,bVal)        if (bVal) iMode |= 0x20; else iMode &= ~0x20   /* (un)set mode bit 5 */
41    
42  #define SYNTHESIS_MODE_GET_CONSTPITCH(iMode)            iMode & 0x01  #define SYNTHESIS_MODE_GET_INTERPOLATE(iMode)           iMode & 0x01
43  #define SYNTHESIS_MODE_GET_LOOP(iMode)                  iMode & 0x02  #define SYNTHESIS_MODE_GET_FILTER(iMode)                iMode & 0x02
44  #define SYNTHESIS_MODE_GET_INTERPOLATE(iMode)           iMode & 0x04  #define SYNTHESIS_MODE_GET_LOOP(iMode)                  iMode & 0x04
45  #define SYNTHESIS_MODE_GET_FILTER(iMode)                iMode & 0x08  #define SYNTHESIS_MODE_GET_CHANNELS(iMode)              iMode & 0x08
46  #define SYNTHESIS_MODE_GET_CHANNELS(iMode)              iMode & 0x10  #define SYNTHESIS_MODE_GET_IMPLEMENTATION(iMode)        iMode & 0x10
 #define SYNTHESIS_MODE_GET_IMPLEMENTATION(iMode)        iMode & 0x20  
47    
48  // that's usually gig::Voice of course, but we make it a macro so we can  // that's usually gig::Voice of course, but we make it a macro so we can
49  // include this code for our synthesis benchmark which uses fake data  // include this code for our synthesis benchmark which uses fake data
# Line 65  namespace LinuxSampler { namespace gig { Line 64  namespace LinuxSampler { namespace gig {
64          STEREO          STEREO
65      };      };
66    
67      template<implementation_t IMPLEMENTATION, channels_t CHANNELS, bool USEFILTER, bool INTERPOLATE, bool DOLOOP, bool CONSTPITCH>      /** @brief Main Synthesis algorithms for the gig::Engine
68         *
69         * Implementation of the main synthesis algorithms of the Gigasampler
70         * format capable sampler engine. This means resampling / interpolation
71         * for pitching the audio signal, looping, filter and amplification.
72         */
73        template<implementation_t IMPLEMENTATION, channels_t CHANNELS, bool DOLOOP, bool USEFILTER, bool INTERPOLATE>
74      class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> {      class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> {
75    
76                // declarations of derived functions (see "Name lookup,
77                // templates, and accessing members of base classes" in
78                // the gcc manual for an explanation of why this is
79                // needed).
80                using __RTMath<IMPLEMENTATION>::Mul;
81                using __RTMath<IMPLEMENTATION>::Float;
82                using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleMonoCPP;
83                using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleStereoCPP;
84    #if CONFIG_ASM && ARCH_X86
85                using LinuxSampler::Resampler<INTERPOLATE>::GetNext4SamplesMonoMMXSSE;
86                using LinuxSampler::Resampler<INTERPOLATE>::GetNext4SamplesStereoMMXSSE;
87    #endif
88    
89          public:          public:
90                /**
91                 * Render audio for the current fragment for the given voice.
92                 * This is the toplevel method of this class.
93                 */            
94              template<typename VOICE_T>              template<typename VOICE_T>
95              inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) {              inline static void SynthesizeSubFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) {
96                  const float panLeft  = Mul(Voice.PanLeft,  Voice.pEngineChannel->GlobalPanLeft);                  const float panLeft  = Mul(Voice.fFinalVolume, Mul(Voice.PanLeft,  Voice.pEngineChannel->GlobalPanLeft));
97                  const float panRight = Mul(Voice.PanRight, Voice.pEngineChannel->GlobalPanRight);                  const float panRight = Mul(Voice.fFinalVolume, Mul(Voice.PanRight, Voice.pEngineChannel->GlobalPanRight));
98                  if (IMPLEMENTATION == ASM_X86_MMX_SSE) {                  if (IMPLEMENTATION == ASM_X86_MMX_SSE) {
99                      float fPos = (float) Voice.Pos;                      float fPos = (float) Voice.Pos;
100                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,                      SynthesizeSubFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
101                                         Voice.pSample->LoopStart,                                         Voice.pSample->LoopStart,
102                                         Voice.pSample->LoopEnd,                                         Voice.pSample->LoopEnd,
103                                         Voice.pSample->LoopSize,                                         Voice.pSample->LoopSize,
104                                         Voice.LoopCyclesLeft,                                         Voice.LoopCyclesLeft,
105                                         (void *)&fPos,                                         (void *)&fPos,
106                                         Voice.PitchBase,                                         &Voice.fFinalPitch,
                                        Voice.PitchBend,  
107                                         &panLeft, &panRight);                                         &panLeft, &panRight);
108                      #if  ARCH_X86                      #if CONFIG_ASM && ARCH_X86
109                      if (INTERPOLATE) EMMS;                      if (INTERPOLATE) EMMS;
110                      #endif                      #endif
111                      Voice.Pos = (double) fPos;                      Voice.Pos = (double) fPos;
112                  } else {                  } else {
113                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,                      SynthesizeSubFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
114                                         Voice.pSample->LoopStart,                                         Voice.pSample->LoopStart,
115                                         Voice.pSample->LoopEnd,                                         Voice.pSample->LoopEnd,
116                                         Voice.pSample->LoopSize,                                         Voice.pSample->LoopSize,
117                                         Voice.LoopCyclesLeft,                                         Voice.LoopCyclesLeft,
118                                         (void *)&Voice.Pos,                                         (void *)&Voice.Pos,
119                                         Voice.PitchBase,                                         &Voice.fFinalPitch,
                                        Voice.PitchBend,  
120                                         &panLeft, &panRight);                                         &panLeft, &panRight);
121                  }                  }
122              }              }
123    
124          //protected:          //protected:
125    
126                /**
127                 * Render audio for the current fragment for the given voice.
128                 * Will be called by the toplevel SynthesizeFragment() method.
129                 */  
130              template<typename VOICE_T>              template<typename VOICE_T>
131              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, const float* PanLeft, const float* PanRight) {              inline static void SynthesizeSubFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint& i, uint& LoopPlayCount, uint LoopStart, uint LoopEnd, uint LoopSize, uint& LoopCyclesLeft, void* Pos, const float* Pitch, const float* PanLeft, const float* PanRight) {
132                  const float loopEnd = Float(LoopEnd);                  const float loopEnd = Float(LoopEnd);
                 const float PBbyPB = Mul(PitchBase, PitchBend);  
133                  const float f_LoopStart = Float(LoopStart);                  const float f_LoopStart = Float(LoopStart);
134                  const float f_LoopSize = Float(LoopSize);                  const float f_LoopSize = Float(LoopSize);
135                  if (DOLOOP) {                  if (DOLOOP) {
136                      if (LoopPlayCount) {                      if (LoopPlayCount) {
137                          // render loop (loop count limited)                          // render loop (loop count limited)
138                          while (i < Samples && LoopCyclesLeft) {                          while (i < Samples && LoopCyclesLeft) {
139                              if (CONSTPITCH) {                              const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd,Pos, *Pitch) + 1); //TODO: instead of +1 we could also round up
140                                  const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd,Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up                              while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
141                                  while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);                              LoopCyclesLeft -= WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);
                             }  
                             else Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);  
                             if (WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos)) LoopCyclesLeft--;  
142                          }                          }
143                          // render on without loop                          // render on without loop
144                          while (i < Samples) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);                          while (i < Samples) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
145                      }                      }
146                      else { // render loop (endless loop)                      else { // render loop (endless loop)
147                          while (i < Samples) {                          while (i < Samples) {
148                              if (CONSTPITCH) {                              const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd, Pos, *Pitch) + 1); //TODO: instead of +1 we could also round up
149                                  const uint processEnd = Min(Samples, i + DiffToLoopEnd(loopEnd, Pos, PBbyPB) + 1); //TODO: instead of +1 we could also round up                              while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
                                 while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);  
                             }  
                             else Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);  
150                              WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);                              WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);
151                          }                          }
152                      }                      }
153                  }                  }
154                  else { // no looping                  else { // no looping
155                      while (i < Samples) { Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);}                      while (i < Samples) { Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight); }
156                  }                  }
157              }              }
158    
159                /**
160                 * Atomicly render a piece for the voice. For the C++
161                 * implementation this means rendering exactly one sample
162                 * point, whereas for the MMX/SSE implementation this means
163                 * rendering 4 sample points.
164                 */
165              template<typename VOICE_T>              template<typename VOICE_T>
166              inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i, const float* PanLeft, const float* PanRight) {              inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i, const float* PanLeft, const float* PanRight) {
167                  Synthesize(pSrc, Pos,                  Synthesize(pSrc, Pos,
168                             Voice.pEngine->pSynthesisParameters[Event::destination_vco][i],                             Voice.fFinalPitch,
169                             Voice.pEngineChannel->pOutputLeft,                             Voice.pEngineChannel->pOutputLeft,
170                             Voice.pEngineChannel->pOutputRight,                             Voice.pEngineChannel->pOutputRight,
171                             i,                             i,
                            Voice.pEngine->pSynthesisParameters[Event::destination_vca],  
172                             PanLeft,                             PanLeft,
173                             PanRight,                             PanRight,
174                             Voice.FilterLeft,                             Voice.FilterLeft,
175                             Voice.FilterRight,                             Voice.FilterRight);
                            Voice.pEngine->pBasicFilterParameters[i],  
                            Voice.pEngine->pMainFilterParameters[i]);  
176              }              }
177    
178                /**
179                 * Returns the difference to the sample's loop end.
180                 */
181              inline static int DiffToLoopEnd(const float& LoopEnd, const void* Pos, const float& Pitch) {              inline static int DiffToLoopEnd(const float& LoopEnd, const void* Pos, const float& Pitch) {
182                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
183                      // pure C++ implementation (thus platform independent)                      #if CONFIG_ASM && ARCH_X86
                     case CPP: {  
                         return uint((LoopEnd - *((double *)Pos)) / Pitch);  
                     }  
                     #if ARCH_X86  
184                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
185                          int result;                          int result;
186                          __asm__ __volatile__ (                          __asm__ __volatile__ (
# Line 175  namespace LinuxSampler { namespace gig { Line 195  namespace LinuxSampler { namespace gig {
195                          );                          );
196                          return result;                          return result;
197                      }                      }
198                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
199                        // pure C++ implementation (thus platform independent)
200                        default: {
201                            return uint((LoopEnd - *((double *)Pos)) / Pitch);
202                        }
203                  }                  }
204              }              }
205    
206              inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {              //TODO: this method is not in use yet, it's intended to be used for pitch=x.0f where we could use integer instead of float as playback position variable
207                inline static int WrapLoop(const int& LoopStart, const int& LoopSize, const int& LoopEnd, int& Pos) {
208                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
209                      // pure C++ implementation (thus platform independent)                      // pure C++ implementation (thus platform independent)
210                      case CPP: {                      default: { //TODO: we can easily eliminate the branch here
211                          double * Pos = (double *)vPos;                          if (Pos < LoopEnd) return 0;
212                          if (*Pos < LoopEnd) return 0;                          Pos = (Pos - LoopEnd) % LoopSize + LoopStart;
                         *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;  
213                          return 1;                          return 1;
214                      }                      }
215                      #if ARCH_X86                  }
216                }
217    
218                /**
219                 * This method handles looping of the RAM playback part of the
220                 * sample, thus repositioning the playback position once the
221                 * loop limit was reached. Note: looping of the disk streaming
222                 * part is handled by libgig (ReadAndLoop() method which will
223                 * be called by the DiskThread).
224                 */
225                inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {
226                    switch (IMPLEMENTATION) {
227                        #if CONFIG_ASM && ARCH_X86
228                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
229                          int result = 0;                          int result = 0;
230                          __asm__ __volatile__ (                          __asm__ __volatile__ (
# Line 201  namespace LinuxSampler { namespace gig { Line 237  namespace LinuxSampler { namespace gig {
237                              //now the fmodf                              //now the fmodf
238                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"
239                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"
240                              "cvttss2si %%xmm1, %%eax    # convert to int\n\t"                              "cvttss2si %%xmm1, %2    # convert to int\n\t"
241                              "cvtsi2ss  %%eax, %%xmm1    # convert back to float\n\t"                              "cvtsi2ss  %2, %%xmm1    # convert back to float\n\t"
242                              "movss    (%4), %%xmm0      # load LoopStart\n\t"                              "movss    (%4), %%xmm0      # load LoopStart\n\t"
243                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"
244                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"
# Line 220  namespace LinuxSampler { namespace gig { Line 256  namespace LinuxSampler { namespace gig {
256                          );                          );
257                          return result;                          return result;
258                      }                      }
259                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
260                        // pure C++ implementation (thus platform independent)
261                        default: {
262                            double * Pos = (double *)vPos;
263                            if (*Pos < LoopEnd) return 0;
264                            *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;
265                            return 1;
266                        }
267                  }                  }
268              }              }
269    
270              inline static void Synthesize(sample_t* pSrc, void* Pos, float& Pitch, float* pOutL, float* pOutR, uint& i, float* Volume, const float* PanL, const float* PanR, Filter& FilterL, Filter& FilterR, biquad_param_t& bqBase, biquad_param_t& bqMain) {              /**
271                 * Atomicly render a piece for the voice. For the C++
272                 * implementation this means rendering exactly one sample
273                 * point, whereas for the MMX/SSE implementation this means
274                 * rendering 4 sample points.
275                 */
276                inline static void Synthesize(sample_t* pSrc, void* Pos, float& Pitch, float* pOutL, float* pOutR, uint& i, const float* PanL, const float* PanR, Filter& FilterL, Filter& FilterR) {
277                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
278                      // pure C++ implementation (thus platform independent)                      // pure C++ implementation (thus platform independent)
279                      case CPP: {                      case CPP: {
280                          switch (CHANNELS) {                          switch (CHANNELS) {
281                              case MONO: {                              case MONO: {
282                                  float samplePoint = GetNextSampleMonoCPP(pSrc, (double *)Pos, Pitch);                                  float samplePoint = GetNextSampleMonoCPP(pSrc, (double *)Pos, Pitch);
283                                  if (USEFILTER) samplePoint = FilterL.Apply(&bqBase, &bqMain, samplePoint);                                  if (USEFILTER) samplePoint = FilterL.Apply(samplePoint);
284                                  pOutL[i] += samplePoint * Volume[i] * *PanL;                                  pOutL[i] += samplePoint * *PanL;
285                                  pOutR[i] += samplePoint * Volume[i] * *PanR;                                  pOutR[i] += samplePoint * *PanR;
286                                  i++;                                  i++;
287                                  break;                                  break;
288                              }                              }
289                              case STEREO: {                              case STEREO: {
290                                  stereo_sample_t samplePoint = GetNextSampleStereoCPP(pSrc, (double *)Pos, Pitch);                                  stereo_sample_t samplePoint = GetNextSampleStereoCPP(pSrc, (double *)Pos, Pitch);
291                                  if (USEFILTER) {                                  if (USEFILTER) {
292                                      samplePoint.left  = FilterL.Apply(&bqBase, &bqMain, samplePoint.left);                                      samplePoint.left  = FilterL.Apply(samplePoint.left);
293                                      samplePoint.right = FilterR.Apply(&bqBase, &bqMain, samplePoint.right);                                      samplePoint.right = FilterR.Apply(samplePoint.right);
294                                  }                                  }
295                                  pOutL[i] += samplePoint.left  * Volume[i] * *PanL;                                  pOutL[i] += samplePoint.left  * *PanL;
296                                  pOutR[i] += samplePoint.right * Volume[i] * *PanR;                                  pOutR[i] += samplePoint.right * *PanR;
297                                  i++;                                  i++;
298                                  break;                                  break;
299                              }                              }
300                          }                          }
301                          break;                          break;
302                      }                      }
303                      #if ARCH_X86                      #if CONFIG_ASM && ARCH_X86
304                      // 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)
305                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
306                          const int ii = i & 0xfffffffc;                          const int ii = i & 0xfffffffc;
# Line 337  namespace LinuxSampler { namespace gig { Line 386  namespace LinuxSampler { namespace gig {
386                                "r" (&pOutR[ii])  /* %1 - must be 16 byte aligned ! */                                "r" (&pOutR[ii])  /* %1 - must be 16 byte aligned ! */
387                          );                          );
388                      }                      }
389                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
390                  }                  }
391              }              }
392      };      };

Legend:
Removed from v.424  
changed lines
  Added in v.738

  ViewVC Help
Powered by ViewVC