1 /*
2  * Copyright (c) 2009, The MilkyTracker Team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14  *   may be used to endorse or promote products derived from this software
15  *   without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *  ChannelMixer.h
32  *  MilkyPlay
33  *
34  *  Created by Peter Barth on Tue Oct 19 2004.
35  *
36  *  This class is pretty much emulating a Gravis Ultrasound with a timer set to 250Hz
37  *  i.e. mixerHandler() will call a timer routine 250 times per second while mixing
38  *  the audio stream in between.
39  */
40 #ifndef __CHANNELMIXER_H__
41 #define __CHANNELMIXER_H__
42 
43 #include "MilkyPlayCommon.h"
44 #include "AudioDriverBase.h"
45 #include "Mixable.h"
46 
47 #define MP_FP_CEIL(x)			(((x)+65535)>>16)
48 #define MP_FP_MUL(a, b)			((mp_sint32)(((mp_int64)(a)*(mp_int64)(b))>>16))
49 
50 #define MP_INCREASESMPPOS(intpart, fracpart, fp, fractbits)	\
51 	intpart+=((fp)>>(fractbits)); \
52 	fracpart+=((fp)&(1<<(fractbits))-1); \
53 	if (((fracpart)>>(fractbits))==1) \
54 	{ \
55 		intpart++; \
56 		fracpart&=(1<<(fractbits))-1; \
57 	}
58 
59 class ChannelMixer;
60 typedef void (ChannelMixer::*TSetFreq)(mp_sint32 c, mp_sint32 f);
61 
62 class MixerSettings
63 {
64 protected:
65 	enum
66 	{
67 		NUMRESAMPLERTYPES = 21,
68 	};
69 
70 public:
71 	// These are arranged in a way, so that the ramping flag toggles with the
72 	// LSB (bit 0) if you count through them
73 	enum ResamplerTypes
74 	{
75 		MIXER_NORMAL,
76 		MIXER_NORMAL_RAMPING,
77 
78 		MIXER_LERPING,
79 		MIXER_LERPING_RAMPING,
80 
81 		MIXER_LAGRANGE,
82 		MIXER_LAGRANGE_RAMPING,
83 
84 		MIXER_SPLINE,
85 		MIXER_SPLINE_RAMPING,
86 
87 		MIXER_SINCTABLE,
88 		MIXER_SINCTABLE_RAMPING,
89 
90 		MIXER_SINC,
91 		MIXER_SINC_RAMPING,
92 
93 		MIXER_AMIGA500,
94 		MIXER_AMIGA500_RAMPING,
95 
96 		MIXER_AMIGA500LED,
97 		MIXER_AMIGA500LED_RAMPING,
98 
99 		MIXER_AMIGA1200,
100 		MIXER_AMIGA1200_RAMPING,
101 
102 		MIXER_AMIGA1200LED,
103 		MIXER_AMIGA1200LED_RAMPING,
104 
105 		MIXER_DUMMY,
106 
107 		MIXER_INVALID
108 	};
109 
110 	enum
111 	{
112 		// pretty large buffer for most systems
113 		BUFFERSIZE_DEFAULT	= 8192
114 	};
115 };
116 
117 class ChannelMixer : public MixerSettings, public Mixable
118 {
119 public:
120 	enum
121 	{
122 		// This is the basis for timing & mixing
123 		// 250hz timer
124 		MP_TIMERFREQ		= 250,
125 		MP_BASEFREQ			= 48000,	// is chosen because (48000 % 250) == 0
126 		// period in samples for MP_TIMERFREQ
127 		MP_BEATLENGTH		= (MP_BASEFREQ/MP_TIMERFREQ),
128 		// mixer state flags
129 		MP_SAMPLE_FILTERLP	= 65536,
130 		MP_SAMPLE_MUTE		= 32768,
131 		MP_SAMPLE_ONESHOT	= 8192,
132 		MP_SAMPLE_FADEOFF	= 4096,
133 		MP_SAMPLE_FADEOUT	= 2048,
134 		MP_SAMPLE_FADEIN	= 1024,
135 		MP_SAMPLE_PLAY		= 256,
136 		MP_SAMPLE_BACKWARD	= 128,
137 
138 		MP_INVALID_VALUE	= 0x7FFFFFFF,
139 		MP_FILTERPRECISION	= 8
140 	};
141 
fixedmul(mp_sint32 a,mp_sint32 b)142 	static inline mp_sint32 fixedmul(mp_sint32 a,mp_sint32 b) { return MP_FP_MUL(a,b); }
fixeddiv(mp_sint32 a,mp_sint32 b)143 	static inline mp_sint32 fixeddiv(mp_sint32 a,mp_sint32 b) { return ((mp_sint32)(((mp_int64)(a)*65536/(mp_int64)(b)))); }
144 
145 	// this is a subset of the channel state which is stored along
146 	// with the time progress, so you can do a look up of the state
147 	// even with large buffer sizes
148 	struct TTimeRecord
149 	{
150 		mp_uint32			flags;					// bit 8 = sample played
151 													// bit 9 = sample direction (0 = forward, 1 = backward)
152 													// bit 10-11 = sample ticker used to represent ramping states
153 													// bit 12 = scheduled to stop
154 													// bit 13 = one shot looping
155 													// bit 15 = mute channel
156 		const mp_sbyte*		sample;					// pointer to sample
157 		mp_sint32			smppos;					// 32 bit integer part of sample position
158 		mp_sint32			volPan;					// 32 bits, upper 16 bits = pan, lower 16 bits = vol
159 		mp_sint32			smplen;
160 		mp_sint32			smpposfrac;				// 16 bit fractional part of sample position
161 		mp_sint32			smpadd;					// 16:16 fixedpoint increment
162 		mp_sint32			loopend;
163 		mp_sint32			loopstart;
164 		mp_sint32			fixedtime;				// for amiga resampler (running time)
165 		mp_sint32			fixedtimefrac;			// for sinc/amiga resamplers (running time fraction)
166 
TTimeRecordTTimeRecord167 		TTimeRecord() :
168 			flags(0),
169 			sample(NULL),
170 			smppos(0),
171 			volPan(0),
172 			smplen(0),
173 			smpposfrac(0),
174 			smpadd(0),
175 			loopend(0),
176 			loopstart(0),
177 			fixedtime(0),
178 			fixedtimefrac(0)
179 		{
180 		}
181 	};
182 
183 	struct TMixerChannel
184 	{
185 		mp_uint32			flags;					// bit 8 = sample played
186 													// bit 9 = sample direction (0 = forward, 1 = backward)
187 													// bit 10-11 = sample ticker used to represent ramping states
188 													// bit 12 = scheduled to stop
189 													// bit 13 = one shot looping
190 													// bit 15 = mute channel
191 		const mp_sbyte*		sample;					// pointer to sample
192 		mp_sint32			smplen;
193 		mp_sint32			smppos;					// 32 bit integer part of sample position
194 		mp_sint32			smpposfrac;				// 16 bit fractional part of sample position
195 		mp_sint32			smpadd;					// 16:16 fixed point increment
196 		mp_sint32			rsmpadd;				// fixed point reciprocal of the increment
197 		mp_sint32			loopend;				// loop end
198 		mp_sint32			loopendcopy;			// Temporary placeholder for one-shot looping
199 		mp_sint32			loopstart;				// loop start
200 
201 		mp_sint32			finalvolr;
202 		mp_sint32			finalvoll;
203 
204 		mp_sint32			vol;
205 		mp_sint32			pan;
206 
207 		mp_sint32			rampFromVolStepR;
208 		mp_sint32			rampFromVolStepL;
209 
210 		mp_sint32			a,b,c;					// Filter coefficients
211 		mp_sint32			currsample;				// sample history for filtering
212 		mp_sint32			prevsample;				// see above
213 
214 		mp_sint32			cutoff;
215 		mp_sint32			resonance;
216 
217 		mp_sint32			fixedtime;				// for amiga resampler (running time)
218 		mp_sint32			fixedtimefrac;			// for sinc/amiga resamplers (running time fraction)
219 
220 		mp_uint32			timeRecordSize;
221 		TTimeRecord*		timeRecord;
222 		mp_sint32			index;					// For Amiga resampler
223 
TMixerChannelTMixerChannel224 		TMixerChannel() :
225 			timeRecordSize(0),
226 			timeRecord(NULL)
227 		{
228 			clear();
229 		}
230 
TMixerChannelTMixerChannel231 		TMixerChannel(bool fastContruction) :
232 			timeRecordSize(0),
233 			timeRecord(NULL)
234 		{
235 		}
236 
~TMixerChannelTMixerChannel237 		~TMixerChannel()
238 		{
239 			if (timeRecord)
240 				delete[] timeRecord;
241 		}
242 
clearTMixerChannel243 		void clear()
244 		{
245 			flags				= 0;
246 			sample				= NULL;
247 			smplen				= 0;
248 			smppos				= 0;
249 			smpposfrac			= 0;
250 			smpadd				= 0;
251 			rsmpadd				= 0;
252 			loopend				= 0;
253 			loopendcopy			= 0;
254 			loopstart			= 0;
255 
256 			finalvolr			= 0;
257 			finalvoll			= 0;
258 
259 			vol					= 0;
260 			pan					= 128;
261 
262 			rampFromVolStepR	= 0;
263 			rampFromVolStepL	= 0;
264 
265 			a = b = c			= 0;
266 			currsample			= 0;
267 			prevsample			= 0;
268 
269 			cutoff				= MP_INVALID_VALUE;
270 			resonance			= MP_INVALID_VALUE;
271 
272 			fixedtime			= 0;
273 			fixedtimefrac		= 0;
274 			index				= -1;		// is filled during runtime
275 
276 			if (timeRecord)
277 				memset(timeRecord, 0, sizeof(TTimeRecord) * timeRecordSize);
278 		}
279 
reallocTimeRecordTMixerChannel280 		void reallocTimeRecord(mp_uint32 size)
281 		{
282 			delete[] timeRecord;
283 			timeRecordSize = size;
284 			timeRecord = new TTimeRecord[size];
285 		}
286 	};
287 
288 	class ResamplerBase
289 	{
290 	private:
291 		// add channels without volume ramping
292 		void addChannelsNormal(ChannelMixer* mixer, mp_uint32 numChannels, mp_sint32* buffer32,mp_sint32 beatNum, mp_sint32 beatlength);
293 		// add channels with volume ramping
294 		void addChannelsRamping(ChannelMixer* mixer, mp_uint32 numChannels, mp_sint32* buffer32,mp_sint32 beatNum, mp_sint32 beatlength);
295 
296 	public:
~ResamplerBase()297 		virtual ~ResamplerBase()
298 		{
299 		}
300 
301 		void addChannels(ChannelMixer* mixer, mp_uint32 numChannels, mp_sint32* buffer32,mp_sint32 beatNum, mp_sint32 beatlength);
302 		void addChannel(TMixerChannel* chn, mp_sint32* buffer32, const mp_sint32 beatlength, const mp_sint32 beatSize);
303 
304 		// walk along the sample
305 		// intpart is the 32 bit integer part of the position
306 		// fracpart is the fractional part of the position
307 		// fp is the amount of samples to advance
308 		// is the resolution of the fractional part in bits (default is 16)
309 		static inline void advanceSamplePosition(mp_sint32& intpart,
310 												 mp_sint32& fracpart,
311 												 const mp_sint32 fp,
312 												 const mp_sint32 fracbits = 16)
313 		{
314 			MP_INCREASESMPPOS(intpart, fracpart, fp, fracbits);
315 		}
316 
317 		// if this resampler is doing ramping
318 		virtual bool isRamping() = 0;
319 		// this resampler can perform a normal block add to the mixing buffer
320 		virtual bool supportsNoChecking() = 0;
321 		// optional: if this resampler is able to perform a full checked walk along the sample
322 		virtual bool supportsFullChecking() = 0;
323 
324 		// see above, you will need to implement at least one of the following
addBlockNoCheck(mp_sint32 * buffer,TMixerChannel * chn,mp_uint32 count)325 		virtual void addBlockNoCheck(mp_sint32* buffer, TMixerChannel* chn, mp_uint32 count)
326 		{
327 			// if this is called your own derived resampler is not properly working
328 			ASSERT(false);
329 		}
330 
331 		// see above for comments
addBlockFull(mp_sint32 * buffer,TMixerChannel * chn,mp_uint32 count)332 		virtual void addBlockFull(mp_sint32* buffer, TMixerChannel* chn, mp_uint32 count)
333 		{
334 			ASSERT(false);
335 		}
336 
337 		// in case the resampler needs to get hold of the current mixing frequency
setFrequency(mp_sint32 frequency)338 		virtual void setFrequency(mp_sint32 frequency) { }
339 
340 		// in case the resampler needs to get hold of the current number of channels
setNumChannels(mp_sint32 num)341 		virtual void setNumChannels(mp_sint32 num) { }
342 	};
343 
344 	friend class ChannelMixer::ResamplerBase;
345 
346 private:
347 	mp_uint32	mixerNumAllocatedChannels;	// Number of channels to be allocated by mixer
348 	mp_uint32	mixerNumActiveChannels;		// Number of channels to be mixed
349 	mp_uint32	mixerLastNumAllocatedChannels;
350 
351 	mp_uint32	mixFrequency;				// Mixing frequency
352 	mp_uint32	rMixFrequency;				// 0x7FFFFFFF/mixFrequency
353 
354 	mp_sint32*  mixbuffBeatPacket;
355 	mp_uint32	mixBufferSize;				// this is the resulting buffer size in 16 bit words
356 
357 	mp_uint32	beatPacketSize;				// size of 1/250 of a second in samples
358 	mp_uint32	numBeatPackets;				// how many of these fit in our buffer size
359 	mp_uint32	lastBeatRemainder;			// used while filling the buffer, if the buffer is not an exact multiple of beatPacketSize
360 
361 	TMixerChannel*	channel;
362 	TMixerChannel*  newChannel;
363 
364 	mp_sint32		masterVolume;			// mixer master volume
365 	mp_sint32		panningSeparation;		// panning separation from 0 (mono) to 256 (full stereo)
366 
367 	ResamplerTypes	resamplerType;
368 	TSetFreq		setFreqFuncTable[NUMRESAMPLERTYPES];			// If different precisions are used, use other frequency calculation procedures
369 	ResamplerBase*  resamplerTable[NUMRESAMPLERTYPES];
370 
371 	bool			paused;
372 	bool			disableMixing;
373 	bool			allowFilters;
374 
375 	void			setFrequency(mp_sint32 frequency);
376 
mixBeatPacket(mp_uint32 numChannels,mp_sint32 * buffer32,mp_sint32 beatPacketIndex,mp_sint32 beatPacketSize)377 	void			mixBeatPacket(mp_uint32 numChannels,
378 								  mp_sint32* buffer32,
379 								  mp_sint32 beatPacketIndex,
380 								  mp_sint32 beatPacketSize)
381 	{
382 		resamplerTable[resamplerType]->addChannels(this, numChannels, buffer32, beatPacketIndex, beatPacketSize);
383 	}
384 
timer(mp_uint32 beatIndex)385 	inline void		timer(mp_uint32 beatIndex)
386 	{
387 		timerHandler(beatIndex <= getNumBeatPackets() ? beatIndex : getNumBeatPackets());
388 	}
389 
390 	void			reallocChannels();
391 	void			clearChannels();
392 
393 public:
394 					ChannelMixer(mp_uint32 numChannels,
395 								 mp_uint32 frequency);
396 
397 	virtual			~ChannelMixer();
398 
getMixBufferSize()399 	mp_uint32		getMixBufferSize() const { return mixBufferSize; }
400 	void			mix(mp_sint32* buffer, mp_uint32 numSamples);
updateSampleCounter(mp_sint32 numSamples)401 	void			updateSampleCounter(mp_sint32 numSamples) { sampleCounter+=numSamples; }
resetSampleCounter()402 	void			resetSampleCounter() { sampleCounter=0; }
403 
404 	mp_sint32		initDevice();
405 	mp_sint32		closeDevice();
406 
407 	void			stop();
408 	mp_sint32		pause();
409 	mp_sint32		resume();
410 
setDisableMixing(bool disableMixing)411 	void			setDisableMixing(bool disableMixing) { this->disableMixing = disableMixing; }
setAllowFilters(bool allowFilters)412 	void			setAllowFilters(bool allowFilters) { this->allowFilters = allowFilters; }
getAllowFilters()413 	bool			getAllowFilters() const { return allowFilters; }
414 
415 	void			resetChannelsFull();
416 	void			resetChannelsWithoutMuting();
417 
418 	void			setResamplerType(ResamplerTypes type);
getResamplerType()419 	ResamplerTypes	getResamplerType() const { return resamplerType; }
isRamping()420 	bool			isRamping()  const { return resamplerTable[resamplerType]->isRamping(); }
421 
422 	virtual mp_sint32 adjustFrequency(mp_uint32 frequency);
getMixFrequency()423 	mp_sint32		getMixFrequency() { return mixFrequency; }
424 
425 	static mp_sint32 beatPacketsToBufferSize(mp_uint32 mixFrequency, mp_uint32 numBeats);
426 	virtual mp_sint32 setBufferSize(mp_uint32 bufferSize);
427 
getBeatPacketSize()428 	mp_uint32		getBeatPacketSize() const { return beatPacketSize; }
getNumBeatPackets()429 	mp_uint32		getNumBeatPackets() const { return mixBufferSize / beatPacketSize; }
430 
431 	// volume control
setMasterVolume(mp_sint32 vol)432 	void			setMasterVolume(mp_sint32 vol) { masterVolume = vol; }
getMasterVolume()433 	mp_sint32		getMasterVolume() const { return masterVolume; }
434 	// panning control
setPanningSeparation(mp_sint32 separation)435 	void			setPanningSeparation(mp_sint32 separation) { panningSeparation = separation; }
getPanningSeparation()436 	mp_sint32		getPanningSeparation() const { return panningSeparation; }
437 
isInitialized()438 	bool			isInitialized() const { return initialized; }
isPlaying()439 	bool			isPlaying() const { return startPlay; }
440 
441 	mp_sint32		getNumActiveChannels();
getNumAllocatedChannels()442 	mp_sint32		getNumAllocatedChannels() const { return mixerNumActiveChannels; }
443 
getSampleCounter()444 	mp_int64		getSampleCounter() const { return sampleCounter; }
445 
446 	mp_sint32		getBeatIndexFromSamplePos(mp_uint32 smpPos) const;
447 
getCurrentResampler()448 	ResamplerBase*  getCurrentResampler() const { return resamplerTable[resamplerType]; }
449 
450 protected:
451 	bool			initialized;
452 	bool			startPlay;
453 
454 	mp_int64		sampleCounter;			// number of samples played (per song)
455 
startMixer()456 	void			startMixer()
457 	{
458 		lastBeatRemainder = 0;
459 	}
460 
461 	void			setNumChannels(mp_uint32 num);
462 
463 	void			setActiveChannels(mp_uint32 num);
464 
465 public:
setVol(mp_sint32 c,mp_sint32 v)466 	void			setVol(mp_sint32 c,mp_sint32 v) { channel[c].vol = v; }
getVol(mp_sint32 c)467 	mp_sint32		getVol(mp_sint32 c) { return channel[c].vol; }
468 
setPan(mp_sint32 c,mp_sint32 p)469 	void			setPan(mp_sint32 c,mp_sint32 p)	{ channel[c].pan = p; }
470 
setFreq(mp_sint32 c,mp_sint32 f)471 	void			setFreq(mp_sint32 c,mp_sint32 f)
472 	{
473 		(this->*setFreqFuncTable[resamplerType])(c,f);
474 	}
475 
476 	// Default low precision calculations
477 	void			setChannelFrequency(mp_sint32 c, mp_sint32 f);
478 
479 	void			setFilterAttributes(mp_sint32 c, mp_sint32 cutoff, mp_sint32 resonance);
480 
481 	void			playSample(mp_sint32 c, // channel
482 							   mp_sbyte* smp, // sample buffer
483 							   mp_sint32 smplen, // sample size
484 							   mp_sint32 smpoffs, // sample offset
485 							   mp_sint32 smpoffsfrac,
486 							   bool smpOffsetWrap,
487 							   mp_sint32 lstart, // loop start
488 							   mp_sint32 len, // loop end
489 							   mp_sint32 flags,
490 							   bool ramp = true);
491 
isChannelPlaying(mp_sint32 c)492 	bool			isChannelPlaying(mp_sint32 c) { return (channel[c].flags&MP_SAMPLE_PLAY) != 0; }
493 
stopSample(mp_sint32 c)494 	void			stopSample(mp_sint32 c) { channel[c].flags&=~(MP_SAMPLE_FADEIN|MP_SAMPLE_FADEOUT); channel[c].flags|=MP_SAMPLE_FADEOFF; }
495 
breakLoop(mp_sint32 c)496 	void			breakLoop(mp_sint32 c) { channel[c].flags&=~3; channel[c].loopend = channel[c].smplen; }
497 
498 	// handle with care
setSamplePos(mp_sint32 c,mp_sint32 pos)499 	void			setSamplePos(mp_sint32 c, mp_sint32 pos) { channel[c].smppos = pos; channel[c].smpposfrac = 0; }
500 
getSamplePos(mp_sint32 c)501 	mp_sint32		getSamplePos(mp_sint32 c) { return channel[c].smppos; }
getSamplePosFrac(mp_sint32 c)502 	mp_sint32		getSamplePosFrac(mp_sint32 c) { return channel[c].smpposfrac; }
503 
setBackward(mp_sint32 c)504 	void			setBackward(mp_sint32 c)
505 	{
506 		if (channel[c].flags & MP_SAMPLE_PLAY)
507 		{
508 			channel[c].flags |= MP_SAMPLE_BACKWARD;
509 			if (channel[c].smppos < channel[c].loopstart)
510 			{
511 				channel[c].smppos = channel[c].loopend;
512 			}
513 		}
514 	}
515 
setForward(mp_sint32 c)516 	void			setForward(mp_sint32 c)
517 	{
518 		if (channel[c].flags & MP_SAMPLE_PLAY)
519 		{
520 			channel[c].flags &= ~MP_SAMPLE_BACKWARD;
521 			if (channel[c].smppos > channel[c].loopend)
522 			{
523 				channel[c].smppos = channel[c].loopstart;
524 			}
525 		}
526 	}
527 
528 	void			muteChannel(mp_sint32 c, bool m);
529 
530 	bool			isChannelMuted(mp_sint32 c);
531 
532 	mp_uint32		getSyncSampleCounter();
533 
534 protected:
535 	// timer procedure for mixing
536 	virtual void	timerHandler(mp_sint32 currentBeatPacket) = 0;
537 	void		   	panToVol(ChannelMixer::TMixerChannel *chn, mp_sint32 &left, mp_sint32 &right);
538 	static mp_sint32 panLUT[257];
539 
540 #ifdef MILKYTRACKER
541 	friend class PlayerController;
542 #endif
543 
544 #ifdef __MPTIMETRACKING__
545 public:
546 	void mixData(mp_sint32 c,
547 				 mp_sint32* buffer,
548 				 mp_sint32 count,
549 				 mp_sint32 sampleShift,
550 				 mp_sint32 fMul = 0,
551 				 mp_sint32 bufferIndex = -1,
552 				 mp_sint32 packetIndex = -1) const;
553 #endif
554 };
555 
556 #endif
557