/[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 336 by senkov, Mon Jan 3 03:33:51 2005 UTC revision 685 by persson, Tue Jul 5 19:30:37 2005 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 Christian Schoenebeck                              *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 64  namespace LinuxSampler { namespace gig { Line 65  namespace LinuxSampler { namespace gig {
65          STEREO          STEREO
66      };      };
67    
68        /** @brief Main Synthesis algorithms for the gig::Engine
69         *
70         * Implementation of the main synthesis algorithms of the Gigasampler
71         * format capable sampler engine. This means resampling / interpolation
72         * for pitching the audio signal, looping, filter and amplification.
73         */
74      template<implementation_t IMPLEMENTATION, channels_t CHANNELS, bool USEFILTER, bool INTERPOLATE, bool DOLOOP, bool CONSTPITCH>      template<implementation_t IMPLEMENTATION, channels_t CHANNELS, bool USEFILTER, bool INTERPOLATE, bool DOLOOP, bool CONSTPITCH>
75      class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> {      class Synthesizer : public __RTMath<IMPLEMENTATION>, public LinuxSampler::Resampler<INTERPOLATE> {
76    
77                // declarations of derived functions (see "Name lookup,
78                // templates, and accessing members of base classes" in
79                // the gcc manual for an explanation of why this is
80                // needed).
81                using __RTMath<IMPLEMENTATION>::Mul;
82                using __RTMath<IMPLEMENTATION>::Float;
83                using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleMonoCPP;
84                using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleStereoCPP;
85    #if CONFIG_ASM && ARCH_X86
86                using LinuxSampler::Resampler<INTERPOLATE>::GetNext4SamplesMonoMMXSSE;
87                using LinuxSampler::Resampler<INTERPOLATE>::GetNext4SamplesStereoMMXSSE;
88    #endif
89    
90          public:          public:
91                /**
92                 * Render audio for the current fragment for the given voice.
93                 * This is the toplevel method of this class.
94                 */            
95              template<typename VOICE_T>              template<typename VOICE_T>
96              inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) {              inline static void SynthesizeFragment(VOICE_T& Voice, uint Samples, sample_t* pSrc, uint i) {
97                    const float panLeft  = Mul(Voice.PanLeft,  Voice.pEngineChannel->GlobalPanLeft);
98                    const float panRight = Mul(Voice.PanRight, Voice.pEngineChannel->GlobalPanRight);
99                  if (IMPLEMENTATION == ASM_X86_MMX_SSE) {                  if (IMPLEMENTATION == ASM_X86_MMX_SSE) {
100                      float fPos = (float) Voice.Pos;                      float fPos = (float) Voice.Pos;
101                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
# Line 78  namespace LinuxSampler { namespace gig { Line 105  namespace LinuxSampler { namespace gig {
105                                         Voice.LoopCyclesLeft,                                         Voice.LoopCyclesLeft,
106                                         (void *)&fPos,                                         (void *)&fPos,
107                                         Voice.PitchBase,                                         Voice.PitchBase,
108                                         Voice.PitchBend);                                         Voice.PitchBend,
109                                           &panLeft, &panRight);
110                        #if CONFIG_ASM && ARCH_X86
111                      if (INTERPOLATE) EMMS;                      if (INTERPOLATE) EMMS;
112                        #endif
113                      Voice.Pos = (double) fPos;                      Voice.Pos = (double) fPos;
114                  } else {                  } else {
115                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,                      SynthesizeFragment(Voice, Samples, pSrc, i, Voice.pSample->LoopPlayCount,
# Line 89  namespace LinuxSampler { namespace gig { Line 119  namespace LinuxSampler { namespace gig {
119                                         Voice.LoopCyclesLeft,                                         Voice.LoopCyclesLeft,
120                                         (void *)&Voice.Pos,                                         (void *)&Voice.Pos,
121                                         Voice.PitchBase,                                         Voice.PitchBase,
122                                         Voice.PitchBend);                                         Voice.PitchBend,
123                                           &panLeft, &panRight);
124                  }                  }
125              }              }
126    
127          //protected:          //protected:
128    
129                /**
130                 * Render audio for the current fragment for the given voice.
131                 * Will be called by the toplevel SynthesizeFragment() method.
132                 */  
133              template<typename VOICE_T>              template<typename VOICE_T>
134              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) {              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) {
135                  const float loopEnd = Float(LoopEnd);                  const float loopEnd = Float(LoopEnd);
136                  const float PBbyPB = Mul(PitchBase, PitchBend);                  const float PBbyPB = Mul(PitchBase, PitchBend);
137                  const float f_LoopStart = Float(LoopStart);                  const float f_LoopStart = Float(LoopStart);
# Line 107  namespace LinuxSampler { namespace gig { Line 142  namespace LinuxSampler { namespace gig {
142                          while (i < Samples && LoopCyclesLeft) {                          while (i < Samples && LoopCyclesLeft) {
143                              if (CONSTPITCH) {                              if (CONSTPITCH) {
144                                  const uint 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
145                                  while (i < processEnd) Synthesize(Voice, Pos, pSrc, i);                                  while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
146                              }                              }
147                              else Synthesize(Voice, Pos, pSrc, i);                              else Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
148                              if (WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos)) LoopCyclesLeft--;                              if (WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos)) LoopCyclesLeft--;
149                          }                          }
150                          // render on without loop                          // render on without loop
151                          while (i < Samples) Synthesize(Voice, Pos, pSrc, i);                          while (i < Samples) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
152                      }                      }
153                      else { // render loop (endless loop)                      else { // render loop (endless loop)
154                          while (i < Samples) {                          while (i < Samples) {
155                              if (CONSTPITCH) {                              if (CONSTPITCH) {
156                                  const uint 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
157                                  while (i < processEnd) Synthesize(Voice, Pos, pSrc, i);                                  while (i < processEnd) Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
158                              }                              }
159                              else Synthesize(Voice, Pos, pSrc, i);                              else Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);
160                              WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);                              WrapLoop(f_LoopStart, f_LoopSize, loopEnd, Pos);
161                          }                          }
162                      }                      }
163                  }                  }
164                  else { // no looping                  else { // no looping
165                      while (i < Samples) { Synthesize(Voice, Pos, pSrc, i);}                      while (i < Samples) { Synthesize(Voice, Pos, pSrc, i, PanLeft, PanRight);}
166                  }                  }
167              }              }
168    
169                /**
170                 * Atomicly render a piece for the voice. For the C++
171                 * implementation this means rendering exactly one sample
172                 * point, whereas for the MMX/SSE implementation this means
173                 * rendering 4 sample points.
174                 */
175              template<typename VOICE_T>              template<typename VOICE_T>
176              inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i) {              inline static void Synthesize(VOICE_T& Voice, void* Pos, sample_t* pSrc, uint& i, const float* PanLeft, const float* PanRight) {
177                  Synthesize(pSrc, Pos,                  Synthesize(pSrc, Pos,
178                             Voice.pEngine->pSynthesisParameters[Event::destination_vco][i],                             Voice.pEngine->pSynthesisParameters[Event::destination_vco][i],
179                             Voice.pEngine->pOutputLeft,                             Voice.pEngineChannel->pOutputLeft,
180                             Voice.pEngine->pOutputRight,                             Voice.pEngineChannel->pOutputRight,
181                             i,                             i,
182                             Voice.pEngine->pSynthesisParameters[Event::destination_vca],                             Voice.pEngine->pSynthesisParameters[Event::destination_vca],
183                             &Voice.PanLeft,                             PanLeft,
184                             &Voice.PanRight,                             PanRight,
185                             Voice.FilterLeft,                             Voice.FilterLeft,
186                             Voice.FilterRight,                             Voice.FilterRight,
187                             Voice.pEngine->pBasicFilterParameters[i],                             Voice.pEngine->pBasicFilterParameters[i],
188                             Voice.pEngine->pMainFilterParameters[i]);                             Voice.pEngine->pMainFilterParameters[i]);
189              }              }
190    
191                /**
192                 * Returns the difference to the sample's loop end.
193                 */
194              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) {
195                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
196                      // pure C++ implementation (thus platform independent)                      #if CONFIG_ASM && ARCH_X86
                     case CPP: {  
                         return uint((LoopEnd - *((double *)Pos)) / Pitch);  
                     }  
                     #if ARCH_X86  
197                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
198                          int result;                          int result;
199                          __asm__ __volatile__ (                          __asm__ __volatile__ (
# Line 168  namespace LinuxSampler { namespace gig { Line 208  namespace LinuxSampler { namespace gig {
208                          );                          );
209                          return result;                          return result;
210                      }                      }
211                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
212                        // pure C++ implementation (thus platform independent)
213                        default: {
214                            return uint((LoopEnd - *((double *)Pos)) / Pitch);
215                        }
216                  }                  }
217              }              }
218    
219                /**
220                 * This method handles looping of the RAM playback part of the
221                 * sample, thus repositioning the playback position once the
222                 * loop limit was reached. Note: looping of the disk streaming
223                 * part is handled by libgig (ReadAndLoop() method which will
224                 * be called by the DiskThread).
225                 */
226              inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {              inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {
227                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
228                      // pure C++ implementation (thus platform independent)                      #if CONFIG_ASM && ARCH_X86
                     case CPP: {  
                         double * Pos = (double *)vPos;  
                         if (*Pos < LoopEnd) return 0;  
                         *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;  
                         return 1;  
                     }  
                     #if ARCH_X86  
229                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
230                          int result = 0;                          int result = 0;
231                          __asm__ __volatile__ (                          __asm__ __volatile__ (
# Line 194  namespace LinuxSampler { namespace gig { Line 238  namespace LinuxSampler { namespace gig {
238                              //now the fmodf                              //now the fmodf
239                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"
240                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"
241                              "cvttss2si %%xmm1, %%eax    # convert to int\n\t"                              "cvttss2si %%xmm1, %2    # convert to int\n\t"
242                              "cvtsi2ss  %%eax, %%xmm1    # convert back to float\n\t"                              "cvtsi2ss  %2, %%xmm1    # convert back to float\n\t"
243                              "movss    (%4), %%xmm0      # load LoopStart\n\t"                              "movss    (%4), %%xmm0      # load LoopStart\n\t"
244                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"
245                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"
# Line 213  namespace LinuxSampler { namespace gig { Line 257  namespace LinuxSampler { namespace gig {
257                          );                          );
258                          return result;                          return result;
259                      }                      }
260                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
261                        // pure C++ implementation (thus platform independent)
262                        default: {
263                            double * Pos = (double *)vPos;
264                            if (*Pos < LoopEnd) return 0;
265                            *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;
266                            return 1;
267                        }
268                  }                  }
269              }              }
270    
271              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) {              /**
272                 * Atomicly render a piece for the voice. For the C++
273                 * implementation this means rendering exactly one sample
274                 * point, whereas for the MMX/SSE implementation this means
275                 * rendering 4 sample points.
276                 */
277                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) {
278                  switch (IMPLEMENTATION) {                  switch (IMPLEMENTATION) {
279                      // pure C++ implementation (thus platform independent)                      // pure C++ implementation (thus platform independent)
280                      case CPP: {                      case CPP: {
# Line 244  namespace LinuxSampler { namespace gig { Line 301  namespace LinuxSampler { namespace gig {
301                          }                          }
302                          break;                          break;
303                      }                      }
304                      #if ARCH_X86                      #if CONFIG_ASM && ARCH_X86
305                      // 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)
306                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
307                          const int ii = i & 0xfffffffc;                          const int ii = i & 0xfffffffc;
# Line 330  namespace LinuxSampler { namespace gig { Line 387  namespace LinuxSampler { namespace gig {
387                                "r" (&pOutR[ii])  /* %1 - must be 16 byte aligned ! */                                "r" (&pOutR[ii])  /* %1 - must be 16 byte aligned ! */
388                          );                          );
389                      }                      }
390                      #endif // ARCH_X86                      #endif // CONFIG_ASM && ARCH_X86
391                  }                  }
392              }              }
393      };      };

Legend:
Removed from v.336  
changed lines
  Added in v.685

  ViewVC Help
Powered by ViewVC