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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1485 - (show annotations) (download) (as text)
Thu Nov 15 23:35:45 2007 UTC (16 years, 5 months ago) by senoner
File MIME type: text/x-c++hdr
File size: 16370 byte(s)
* win32 port, work in progress:
* added MME MIDI Input driver
* Resampler.h, gig/Synthesizer.h:
* changed return type of getSample() from int to int32_t

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 * *
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 #include "../../common/global_private.h"
28 #include "../../common/RTMath.h"
29 #include "../common/Resampler.h"
30 #include "Filter.h"
31 #include "SynthesisParam.h"
32
33 #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_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
41 #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 #define SYNTHESIS_MODE_GET_BITDEPTH24(iMode) iMode & 0x10
46 #define SYNTHESIS_MODE_GET_IMPLEMENTATION(iMode) iMode & 0x20
47
48
49 namespace LinuxSampler { namespace gig {
50
51 typedef void SynthesizeFragment_Fn(SynthesisParam* pFinalParam, Loop* pLoop);
52
53 void* GetSynthesisFunction(const int SynthesisMode);
54 void RunSynthesisFunction(const int SynthesisMode, SynthesisParam* pFinalParam, Loop* pLoop);
55
56 enum channels_t {
57 MONO,
58 STEREO
59 };
60
61 /** @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 template<channels_t CHANNELS, bool DOLOOP, bool USEFILTER, bool INTERPOLATE, bool BITDEPTH24>
68 class Synthesizer : public __RTMath<CPP>, public LinuxSampler::Resampler<INTERPOLATE,BITDEPTH24> {
69
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 //using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleMonoCPP;
75 //using LinuxSampler::Resampler<INTERPOLATE>::GetNextSampleStereoCPP;
76 using LinuxSampler::Resampler<INTERPOLATE,BITDEPTH24>::Interpolate1StepMonoCPP;
77 using LinuxSampler::Resampler<INTERPOLATE,BITDEPTH24>::Interpolate1StepStereoCPP;
78
79 public:
80 //protected:
81
82 static void SynthesizeSubFragment(SynthesisParam* pFinalParam, Loop* pLoop) {
83 if (DOLOOP) {
84 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 // render loop (loop count limited)
89 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 }
93 // render on without loop
94 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 }
100 }
101 } else { // no looping
102 SynthesizeSubSubFragment(pFinalParam, pFinalParam->uiToGo);
103 }
104 }
105
106 /**
107 * Returns the difference to the sample's loop end.
108 */
109 inline static int DiffToLoopEnd(const float& LoopEnd, const void* Pos, const float& Pitch) {
110 return uint((LoopEnd - *((double *)Pos)) / Pitch);
111 }
112
113 #if 0
114 //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 //TODO: we can easily eliminate the branch here
117 if (Pos < LoopEnd) return 0;
118 Pos = (Pos - LoopEnd) % LoopSize + LoopStart;
119 return 1;
120 }
121 #endif
122
123 /**
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 inline static int WrapLoop(const float& LoopStart, const float& LoopSize, const float& LoopEnd, void* vPos) {
131 double * Pos = (double *)vPos;
132 if (*Pos < LoopEnd) return 0;
133 *Pos = fmod(*Pos - LoopEnd, LoopSize) + LoopStart;
134 return 1;
135 }
136
137 inline static int32_t getSample(sample_t* src, int pos) {
138 if (BITDEPTH24) {
139 pos *= 3;
140 #if WORDS_BIGENDIAN
141 unsigned char* p = (unsigned char*)src;
142 return p[pos] << 8 | p[pos + 1] << 16 | p[pos + 2] << 24;
143 #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 (*((int32_t *)(&((char *)(src))[pos])))<<8;
147 #endif
148 } else {
149 return src[pos];
150 }
151 }
152
153 static void SynthesizeSubSubFragment(SynthesisParam* pFinalParam, uint uiToGo) {
154 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 switch (CHANNELS) {
164 case MONO: {
165 float samplePoint;
166 if (INTERPOLATE) {
167 double dPos = pFinalParam->dPos;
168 float fPitch = pFinalParam->fFinalPitch;
169 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 #ifdef CONFIG_INTERPOLATE_VOLUME
175 fVolumeL += fDeltaL;
176 fVolumeR += fDeltaR;
177 #endif
178 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 #ifdef CONFIG_INTERPOLATE_VOLUME
185 fVolumeL += fDeltaL;
186 fVolumeR += fDeltaR;
187 #endif
188 pOutL[i] += samplePoint * fVolumeL;
189 pOutR[i] += samplePoint * fVolumeR;
190 }
191 }
192 pFinalParam->dPos = dPos;
193 } else { // no interpolation
194 int pos_offset = (int) pFinalParam->dPos;
195 if (USEFILTER) {
196 Filter filterL = pFinalParam->filterLeft;
197 for (int i = 0; i < uiToGo; ++i) {
198 samplePoint = getSample(pSrc, i + pos_offset);
199 samplePoint = filterL.Apply(samplePoint);
200 #ifdef CONFIG_INTERPOLATE_VOLUME
201 fVolumeL += fDeltaL;
202 fVolumeR += fDeltaR;
203 #endif
204 pOutL[i] += samplePoint * fVolumeL;
205 pOutR[i] += samplePoint * fVolumeR;
206 }
207 } else { // no filter needed
208 for (int i = 0; i < uiToGo; ++i) {
209 samplePoint = getSample(pSrc, i + pos_offset);
210 #ifdef CONFIG_INTERPOLATE_VOLUME
211 fVolumeL += fDeltaL;
212 fVolumeR += fDeltaR;
213 #endif
214 pOutL[i] += samplePoint * fVolumeL;
215 pOutR[i] += samplePoint * fVolumeR;
216 }
217 }
218 pFinalParam->dPos += uiToGo;
219 }
220 break;
221 }
222 case STEREO: {
223 stereo_sample_t samplePoint;
224 if (INTERPOLATE) {
225 double dPos = pFinalParam->dPos;
226 float fPitch = pFinalParam->fFinalPitch;
227 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 #ifdef CONFIG_INTERPOLATE_VOLUME
235 fVolumeL += fDeltaL;
236 fVolumeR += fDeltaR;
237 #endif
238 pOutL[i] += samplePoint.left * fVolumeL;
239 pOutR[i] += samplePoint.right * fVolumeR;
240 }
241 } else { // no filter needed
242 for (int i = 0; i < uiToGo; ++i) {
243 samplePoint = Interpolate1StepStereoCPP(pSrc, &dPos, fPitch);
244 #ifdef CONFIG_INTERPOLATE_VOLUME
245 fVolumeL += fDeltaL;
246 fVolumeR += fDeltaR;
247 #endif
248 pOutL[i] += samplePoint.left * fVolumeL;
249 pOutR[i] += samplePoint.right * fVolumeR;
250 }
251 }
252 pFinalParam->dPos = dPos;
253 } else { // no interpolation
254 int pos_offset = ((int) pFinalParam->dPos) << 1;
255 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 samplePoint.left = getSample(pSrc, ii + pos_offset);
260 samplePoint.right = getSample(pSrc, ii + pos_offset + 1);
261 samplePoint.left = filterL.Apply(samplePoint.left);
262 samplePoint.right = filterR.Apply(samplePoint.right);
263 #ifdef CONFIG_INTERPOLATE_VOLUME
264 fVolumeL += fDeltaL;
265 fVolumeR += fDeltaR;
266 #endif
267 pOutL[i] += samplePoint.left * fVolumeL;
268 pOutR[i] += samplePoint.right * fVolumeR;
269 }
270 } else { // no filter needed
271 for (int i = 0, ii = 0; i < uiToGo; ++i, ii+=2) {
272 samplePoint.left = getSample(pSrc, ii + pos_offset);
273 samplePoint.right = getSample(pSrc, ii + pos_offset + 1);
274 #ifdef CONFIG_INTERPOLATE_VOLUME
275 fVolumeL += fDeltaL;
276 fVolumeR += fDeltaR;
277 #endif
278 pOutL[i] += samplePoint.left * fVolumeL;
279 pOutR[i] += samplePoint.right * fVolumeR;
280 }
281 }
282 pFinalParam->dPos += uiToGo;
283 }
284 break;
285 }
286 }
287 pFinalParam->fFinalVolumeLeft = fVolumeL;
288 pFinalParam->fFinalVolumeRight = fVolumeR;
289 pFinalParam->pOutRight += uiToGo;
290 pFinalParam->pOutLeft += uiToGo;
291 pFinalParam->uiToGo -= uiToGo;
292 }
293 };
294
295 }} // namespace LinuxSampler::gig
296
297 #endif // __LS_GIG_SYNTHESIZER_H__

  ViewVC Help
Powered by ViewVC