/[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 332 by senkov, Sat Jan 1 03:06:06 2005 UTC revision 563 by schoenebeck, Sun May 22 20:43:32 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 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  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)                      // pure C++ implementation (thus platform independent)
# Line 172  namespace LinuxSampler { namespace gig { Line 216  namespace LinuxSampler { namespace gig {
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)                      // pure C++ implementation (thus platform independent)
# Line 183  namespace LinuxSampler { namespace gig { Line 234  namespace LinuxSampler { namespace gig {
234                      }                      }
235                      #if ARCH_X86                      #if ARCH_X86
236                      case ASM_X86_MMX_SSE: {                      case ASM_X86_MMX_SSE: {
237                          int result;                          int result = 0;
238                          __asm__ __volatile__ (                          __asm__ __volatile__ (
239                              "movss  (%2), %%xmm0          # load LoopEnd\n\t"                              "movss  (%2), %%xmm0          # load LoopEnd\n\t"
240                              "movss  (%1), %%xmm1          # load Pos\n\t"                              "movss  (%1), %%xmm1          # load Pos\n\t"
241                              "comiss %%xmm0, %%xmm1      # LoopEnd <> Pos\n\t"                              "comiss %%xmm0, %%xmm1      # LoopEnd <> Pos\n\t"
                             "movl    $0,%%eax            # result = 0\n\t"  
242                              "jb     1f                  # jump if no work needs to be done\n\t"                              "jb     1f                  # jump if no work needs to be done\n\t"
243                              "movss    (%3), %%xmm2        # load LoopSize\n\t"                              "movss    (%3), %%xmm2        # load LoopSize\n\t"
244                              "subss    %%xmm0, %%xmm1    # Pos - LoopEnd\n\t"                              "subss    %%xmm0, %%xmm1    # Pos - LoopEnd\n\t"
245                              //now the fmodf                              //now the fmodf
246                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"                              "movss    %%xmm1, %%xmm3    # xmm3 = (Pos - LoopEnd)\n\t"
247                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"                              "divss    %%xmm2, %%xmm1    # (Pos - LoopEnd) / LoopSize\n\t"
248                              "cvttss2si %%xmm1, %%eax    # convert to int\n\t"                              "cvttss2si %%xmm1, %2    # convert to int\n\t"
249                              "cvtsi2ss  %%eax, %%xmm1    # convert back to float\n\t"                              "cvtsi2ss  %2, %%xmm1    # convert back to float\n\t"
250                              "movss    (%4), %%xmm0      # load LoopStart\n\t"                              "movss    (%4), %%xmm0      # load LoopStart\n\t"
251                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"                              "mulss    %%xmm2, %%xmm1    # LoopSize * int((Pos-LoopEnd)/LoopSize)\n\t"
252                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"                              "subss    %%xmm1, %%xmm3    # xmm2 = fmodf(Pos - LoopEnd, LoopSize)\n\t"
253                              //done with fmodf                              //done with fmodf
254                              "addss    %%xmm0, %%xmm3      # add LoopStart\n\t"                              "addss    %%xmm0, %%xmm3      # add LoopStart\n\t"
255                              "movss    %%xmm3, (%1)        # update Pos\n\t"                              "movss    %%xmm3, (%1)        # update Pos\n\t"
256                              "movl    $1,%%eax            # result = 1\n\t"                              "movl    $1, (%0)             # result = 1\n\t"
257                              ".balign 16 \n\t"                              ".balign 16 \n\t"
258                              "1:\n\t"                              "1:\n\t"
259                              : "=a" (result)     /* %0 */                              :: "r" (&result),   /* %0 */
260                              : "r"  (vPos),      /* %1 */                                "r"  (vPos),      /* %1 */
261                                "r"  (&LoopEnd),  /* %2 */                                "r"  (&LoopEnd),  /* %2 */
262                                "r"  (&LoopSize), /* %3 */                                "r"  (&LoopSize), /* %3 */
263                                "r"  (&LoopStart) /* %4 */                                "r"  (&LoopStart) /* %4 */
# Line 218  namespace LinuxSampler { namespace gig { Line 268  namespace LinuxSampler { namespace gig {
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: {

Legend:
Removed from v.332  
changed lines
  Added in v.563

  ViewVC Help
Powered by ViewVC