/[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 877 - (hide annotations) (download) (as text)
Sun Jun 25 13:54:17 2006 UTC (17 years, 10 months ago) by persson
File MIME type: text/x-c++hdr
File size: 15332 byte(s)
* new filter implementation, which is more accurate and supports all
  filter types including bandreject and lowpass turbo

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 "Filter.h"
31 schoenebeck 770 #include "SynthesisParam.h"
32 schoenebeck 320
33 schoenebeck 738 #define SYNTHESIS_MODE_SET_INTERPOLATE(iMode,bVal) if (bVal) iMode |= 0x01; else iMode &= ~0x01 /* (un)set mode bit 0 */
34     #define SYNTHESIS_MODE_SET_FILTER(iMode,bVal) if (bVal) iMode |= 0x02; else iMode &= ~0x02 /* (un)set mode bit 1 */
35     #define SYNTHESIS_MODE_SET_LOOP(iMode,bVal) if (bVal) iMode |= 0x04; else iMode &= ~0x04 /* (un)set mode bit 2 */
36     #define SYNTHESIS_MODE_SET_CHANNELS(iMode,bVal) if (bVal) iMode |= 0x08; else iMode &= ~0x08 /* (un)set mode bit 3 */
37     #define SYNTHESIS_MODE_SET_IMPLEMENTATION(iMode,bVal) if (bVal) iMode |= 0x10; else iMode &= ~0x10 /* (un)set mode bit 4 */
38 schoenebeck 770 #define SYNTHESIS_MODE_SET_PROFILING(iMode,bVal) if (bVal) iMode |= 0x20; else iMode &= ~0x20 /* (un)set mode bit 5 */
39 schoenebeck 320
40 schoenebeck 738 #define SYNTHESIS_MODE_GET_INTERPOLATE(iMode) iMode & 0x01
41     #define SYNTHESIS_MODE_GET_FILTER(iMode) iMode & 0x02
42     #define SYNTHESIS_MODE_GET_LOOP(iMode) iMode & 0x04
43     #define SYNTHESIS_MODE_GET_CHANNELS(iMode) iMode & 0x08
44     #define SYNTHESIS_MODE_GET_IMPLEMENTATION(iMode) iMode & 0x10
45    
46 schoenebeck 320 namespace LinuxSampler { namespace gig {
47    
48 schoenebeck 770 typedef void SynthesizeFragment_Fn(SynthesisParam* pFinalParam, Loop* pLoop);
49 schoenebeck 320
50     void* GetSynthesisFunction(const int SynthesisMode);
51 schoenebeck 770 void RunSynthesisFunction(const int SynthesisMode, SynthesisParam* pFinalParam, Loop* pLoop);
52 schoenebeck 320
53     enum channels_t {
54     MONO,
55     STEREO
56     };
57    
58 schoenebeck 563 /** @brief Main Synthesis algorithms for the gig::Engine
59     *
60     * Implementation of the main synthesis algorithms of the Gigasampler
61     * format capable sampler engine. This means resampling / interpolation
62     * for pitching the audio signal, looping, filter and amplification.
63     */
64 schoenebeck 770 template<channels_t CHANNELS, bool DOLOOP, bool USEFILTER, bool INTERPOLATE>
65     class Synthesizer : public __RTMath<CPP>, public LinuxSampler::Resampler<INTERPOLATE> {
66 persson 497
67     // declarations of derived functions (see "Name lookup,
68     // templates, and accessing members of base classes" in
69     // the gcc manual for an explanation of why this is
70     // needed).
71 schoenebeck 770 //using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleMonoCPP;
72     //using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleStereoCPP;
73     using LinuxSampler::Resampler<INTERPOLATE>::Interpolate1StepMonoCPP;
74     using LinuxSampler::Resampler<INTERPOLATE>::Interpolate1StepStereoCPP;
75 persson 497
76 schoenebeck 320 public:
77     //protected:
78    
79 schoenebeck 770 static void SynthesizeSubFragment(SynthesisParam* pFinalParam, Loop* pLoop) {
80 schoenebeck 320 if (DOLOOP) {
81 schoenebeck 770 const float fLoopEnd = Float(pLoop->uiEnd);
82     const float fLoopStart = Float(pLoop->uiStart);
83     const float fLoopSize = Float(pLoop->uiSize);
84     if (pLoop->uiTotalCycles) {
85 schoenebeck 320 // render loop (loop count limited)
86 schoenebeck 770 for (; pFinalParam->uiToGo > 0 && pLoop->uiCyclesLeft; pLoop->uiCyclesLeft -= WrapLoop(fLoopStart, fLoopSize, fLoopEnd, &pFinalParam->dPos)) {
87     const uint uiToGo = Min(pFinalParam->uiToGo, DiffToLoopEnd(fLoopEnd, &pFinalParam->dPos, pFinalParam->fFinalPitch) + 1); //TODO: instead of +1 we could also round up
88     SynthesizeSubSubFragment(pFinalParam, uiToGo);
89 schoenebeck 320 }
90     // render on without loop
91 schoenebeck 770 SynthesizeSubSubFragment(pFinalParam, pFinalParam->uiToGo);
92     } else { // render loop (endless loop)
93     for (; pFinalParam->uiToGo > 0; WrapLoop(fLoopStart, fLoopSize, fLoopEnd, &pFinalParam->dPos)) {
94     const uint uiToGo = Min(pFinalParam->uiToGo, DiffToLoopEnd(fLoopEnd, &pFinalParam->dPos, pFinalParam->fFinalPitch) + 1); //TODO: instead of +1 we could also round up
95     SynthesizeSubSubFragment(pFinalParam, uiToGo);
96 schoenebeck 320 }
97     }
98 schoenebeck 770 } else { // no looping
99     SynthesizeSubSubFragment(pFinalParam, pFinalParam->uiToGo);
100 schoenebeck 320 }
101     }
102    
103 schoenebeck 563 /**
104     * Returns the difference to the sample's loop end.
105     */
106 schoenebeck 320 inline static int DiffToLoopEnd(const float& LoopEnd, const void* Pos, const float& Pitch) {
107 schoenebeck 770 return uint((LoopEnd - *((double *)Pos)) / Pitch);
108 schoenebeck 320 }
109    
110 schoenebeck 770 #if 0
111 schoenebeck 738 //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
112     inline static int WrapLoop(const int& LoopStart, const int& LoopSize, const int& LoopEnd, int& Pos) {
113 schoenebeck 770 //TODO: we can easily eliminate the branch here
114     if (Pos < LoopEnd) return 0;
115     Pos = (Pos - LoopEnd) % LoopSize + LoopStart;
116     return 1;
117 schoenebeck 738 }
118 schoenebeck 770 #endif
119 schoenebeck 738
120 schoenebeck 563 /**
121     * This method handles looping of the RAM playback part of the
122     * sample, thus repositioning the playback position once the
123     * loop limit was reached. Note: looping of the disk streaming
124     * part is handled by libgig (ReadAndLoop() method which will
125     * be called by the DiskThread).
126     */
127 schoenebeck 320 inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {
128 schoenebeck 770 double * Pos = (double *)vPos;
129     if (*Pos < LoopEnd) return 0;
130     *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;
131     return 1;
132 schoenebeck 320 }
133    
134 schoenebeck 770 static void SynthesizeSubSubFragment(SynthesisParam* pFinalParam, uint uiToGo) {
135 persson 830 float fVolumeL = pFinalParam->fFinalVolumeLeft;
136     float fVolumeR = pFinalParam->fFinalVolumeRight;
137     sample_t* pSrc = pFinalParam->pSrc;
138     float* pOutL = pFinalParam->pOutLeft;
139     float* pOutR = pFinalParam->pOutRight;
140     #ifdef CONFIG_INTERPOLATE_VOLUME
141     float fDeltaL = pFinalParam->fFinalVolumeDeltaLeft;
142     float fDeltaR = pFinalParam->fFinalVolumeDeltaRight;
143     #endif
144 schoenebeck 770 switch (CHANNELS) {
145     case MONO: {
146 persson 830 float samplePoint;
147 schoenebeck 770 if (INTERPOLATE) {
148 persson 830 double dPos = pFinalParam->dPos;
149     float fPitch = pFinalParam->fFinalPitch;
150 schoenebeck 770 if (USEFILTER) {
151     Filter filterL = pFinalParam->filterLeft;
152     for (int i = 0; i < uiToGo; ++i) {
153     samplePoint = Interpolate1StepMonoCPP(pSrc, &dPos, fPitch);
154     samplePoint = filterL.Apply(samplePoint);
155 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
156     fVolumeL += fDeltaL;
157     fVolumeR += fDeltaR;
158     #endif
159 schoenebeck 770 pOutL[i] += samplePoint * fVolumeL;
160     pOutR[i] += samplePoint * fVolumeR;
161     }
162     } else { // no filter needed
163     for (int i = 0; i < uiToGo; ++i) {
164     samplePoint = Interpolate1StepMonoCPP(pSrc, &dPos, fPitch);
165 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
166     fVolumeL += fDeltaL;
167     fVolumeR += fDeltaR;
168     #endif
169 schoenebeck 770 pOutL[i] += samplePoint * fVolumeL;
170     pOutR[i] += samplePoint * fVolumeR;
171     }
172 schoenebeck 320 }
173 persson 830 pFinalParam->dPos = dPos;
174 schoenebeck 770 } else { // no interpolation
175 persson 830 int pos_offset = (int) pFinalParam->dPos;
176 schoenebeck 770 if (USEFILTER) {
177     Filter filterL = pFinalParam->filterLeft;
178     for (int i = 0; i < uiToGo; ++i) {
179     samplePoint = pSrc[i + pos_offset];
180     samplePoint = filterL.Apply(samplePoint);
181 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
182     fVolumeL += fDeltaL;
183     fVolumeR += fDeltaR;
184     #endif
185 schoenebeck 770 pOutL[i] += samplePoint * fVolumeL;
186     pOutR[i] += samplePoint * fVolumeR;
187 schoenebeck 320 }
188 schoenebeck 770 } else { // no filter needed
189     for (int i = 0; i < uiToGo; ++i) {
190     samplePoint = pSrc[i + pos_offset];
191 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
192     fVolumeL += fDeltaL;
193     fVolumeR += fDeltaR;
194     #endif
195 schoenebeck 770 pOutL[i] += samplePoint * fVolumeL;
196     pOutR[i] += samplePoint * fVolumeR;
197     }
198 schoenebeck 320 }
199 persson 830 pFinalParam->dPos += uiToGo;
200 schoenebeck 320 }
201     break;
202     }
203 schoenebeck 770 case STEREO: {
204 persson 830 stereo_sample_t samplePoint;
205 schoenebeck 770 if (INTERPOLATE) {
206 persson 830 double dPos = pFinalParam->dPos;
207     float fPitch = pFinalParam->fFinalPitch;
208 schoenebeck 770 if (USEFILTER) {
209     Filter filterL = pFinalParam->filterLeft;
210     Filter filterR = pFinalParam->filterRight;
211     for (int i = 0; i < uiToGo; ++i) {
212     samplePoint = Interpolate1StepStereoCPP(pSrc, &dPos, fPitch);
213     samplePoint.left = filterL.Apply(samplePoint.left);
214     samplePoint.right = filterR.Apply(samplePoint.right);
215 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
216     fVolumeL += fDeltaL;
217     fVolumeR += fDeltaR;
218     #endif
219 schoenebeck 770 pOutL[i] += samplePoint.left * fVolumeL;
220     pOutR[i] += samplePoint.right * fVolumeR;
221 schoenebeck 320 }
222 schoenebeck 770 } else { // no filter needed
223     for (int i = 0; i < uiToGo; ++i) {
224     samplePoint = Interpolate1StepStereoCPP(pSrc, &dPos, fPitch);
225 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
226     fVolumeL += fDeltaL;
227     fVolumeR += fDeltaR;
228     #endif
229 schoenebeck 770 pOutL[i] += samplePoint.left * fVolumeL;
230     pOutR[i] += samplePoint.right * fVolumeR;
231     }
232 schoenebeck 320 }
233 persson 830 pFinalParam->dPos = dPos;
234 schoenebeck 770 } else { // no interpolation
235 persson 830 int pos_offset = ((int) pFinalParam->dPos) << 1;
236 schoenebeck 770 if (USEFILTER) {
237     Filter filterL = pFinalParam->filterLeft;
238     Filter filterR = pFinalParam->filterRight;
239     for (int i = 0, ii = 0; i < uiToGo; ++i, ii+=2) {
240     samplePoint.left = pSrc[ii + pos_offset];
241     samplePoint.right = pSrc[ii + pos_offset + 1];
242     samplePoint.left = filterL.Apply(samplePoint.left);
243     samplePoint.right = filterR.Apply(samplePoint.right);
244 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
245     fVolumeL += fDeltaL;
246     fVolumeR += fDeltaR;
247     #endif
248 schoenebeck 770 pOutL[i] += samplePoint.left * fVolumeL;
249     pOutR[i] += samplePoint.right * fVolumeR;
250 schoenebeck 320 }
251 schoenebeck 770 } else { // no filter needed
252     for (int i = 0, ii = 0; i < uiToGo; ++i, ii+=2) {
253     samplePoint.left = pSrc[ii + pos_offset];
254     samplePoint.right = pSrc[ii + pos_offset + 1];
255 persson 830 #ifdef CONFIG_INTERPOLATE_VOLUME
256     fVolumeL += fDeltaL;
257     fVolumeR += fDeltaR;
258     #endif
259 schoenebeck 770 pOutL[i] += samplePoint.left * fVolumeL;
260     pOutR[i] += samplePoint.right * fVolumeR;
261     }
262 schoenebeck 320 }
263 persson 830 pFinalParam->dPos += uiToGo;
264 schoenebeck 320 }
265 schoenebeck 770 break;
266 schoenebeck 320 }
267     }
268 persson 830 pFinalParam->fFinalVolumeLeft = fVolumeL;
269     pFinalParam->fFinalVolumeRight = fVolumeR;
270 schoenebeck 770 pFinalParam->pOutRight += uiToGo;
271     pFinalParam->pOutLeft += uiToGo;
272     pFinalParam->uiToGo -= uiToGo;
273 schoenebeck 320 }
274     };
275    
276     }} // namespace LinuxSampler::gig
277    
278     #endif // __LS_GIG_SYNTHESIZER_H__

  ViewVC Help
Powered by ViewVC