/[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 1484 - (hide annotations) (download) (as text)
Thu Nov 15 13:24:41 2007 UTC (16 years, 5 months ago) by senoner
File MIME type: text/x-c++hdr
File size: 16362 byte(s)
* Stream.h: added a missing divide by BytesPerSample in GetWriteSpace()
* since this function is currently only used in the stream's
* qsort() compare function, it did trigger any bugs
* Resampler.h, Synthesizer.h:
* cubic interpolation now works in 24bit mode too
* faster method to read 24bit words on little endian machines (x86):
*  replaced 3 byte reads + shifts with a 1 unaligned 32bit read and shift

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

  ViewVC Help
Powered by ViewVC