1 /*-----------------------------------------------------------------------------
2 
3 	ST-Sound ( YM files player library )
4 
5 	YM Music Driver
6 
7 -----------------------------------------------------------------------------*/
8 
9 /*-----------------------------------------------------------------------------
10 * ST-Sound, ATARI-ST Music Emulator
11 * Copyright (c) 1995-1999 Arnaud Carre ( http://leonard.oxg.free.fr )
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 -----------------------------------------------------------------------------*/
36 
37 #include "config.h"
38 #ifdef HAVE_STRING_H
39 #include <string.h>
40 #endif
41 #include <stdlib.h>
42 #include <assert.h>
43 #include "YmMusic.h"
44 
45 #define	_LINEAR_OVRS				// Activate linear oversampling (best quality) Only used for DigiMix and UniversalTracker YM file type
46 
47 
48 // ATARI-ST MFP chip predivisor
49 static	const ymint	mfpPrediv[8] = {0,4,10,16,50,64,100,200};
50 
51 
52 
CYmMusic(ymint _replayRate)53 CYmMusic::CYmMusic(ymint _replayRate)
54 {
55 
56 	pBigMalloc = NULL;
57 	pSongName = NULL;
58 	pSongAuthor = NULL;
59 	pSongComment = NULL;
60 	pSongType = NULL;
61 	pSongPlayer = NULL;
62 
63 	pBigSampleBuffer = NULL;
64 	pMixBlock = NULL;
65 
66 	replayRate = _replayRate;
67 	innerSamplePos = 0;
68 	currentPos = 0;
69 	nbDrum = 0;
70 	pDrumTab = NULL;
71 	setLoopMode(YMFALSE);
72 
73 	m_pTimeInfo = NULL;
74 }
75 
setTimeControl(ymbool bTime)76 void	CYmMusic::setTimeControl(ymbool bTime)
77 {
78 		if (bTime)
79 			attrib |= A_TIMECONTROL;
80 		else
81 			attrib &= (~A_TIMECONTROL);
82 }
83 
~CYmMusic()84 CYmMusic::~CYmMusic()
85 {
86 		stop();
87 		unLoad();
88 }
89 
setLoopMode(ymbool bLoopMode)90 void	CYmMusic::setLoopMode(ymbool bLoopMode)
91 {
92 		bLoop = bLoopMode;
93 }
94 
setPlayerRate(ymint rate)95 void	CYmMusic::setPlayerRate(ymint rate)
96 {
97 		playerRate = rate;
98 }
99 
getPos()100 ymu32 CYmMusic::getPos()
101 {
102 	if ((songType>=YM_MIX1) && (songType<YM_MIXMAX))
103 	{
104 		// avoid overflow after 97 seconds and keep only 32bit computing
105 		return m_iMusicPosInMs;
106 	}
107 	else if ((nbFrame>0) && (playerRate>0))
108 	{
109 		return ((ymu32)currentFrame*1000)/(ymu32)playerRate;
110 	}
111 	else
112 		return 0;
113 
114 }
115 
getMusicTime(void)116 ymu32	CYmMusic::getMusicTime(void)
117 {
118 
119 	if ((songType>=YM_MIX1) && (songType<YM_MIXMAX))
120 	{
121 		return m_musicLenInMs;
122 	}
123 	else if ((nbFrame>0) && (playerRate>0))
124 	{
125 		return ((ymu32)nbFrame*1000)/(ymu32)playerRate;
126 	}
127 	else
128 		return 0;
129 
130 }
131 
132 
setMixTime(ymu32 time)133 void	CYmMusic::setMixTime(ymu32 time)
134 {
135 	if (time > m_musicLenInMs)
136 		return;
137 
138 	assert(m_pTimeInfo);
139 	for (int i=0;i<m_nbTimeKey;i++)
140 	{
141 		ymu32 tEnd = i < (m_nbTimeKey-1) ? m_pTimeInfo[i+1].time : m_musicLenInMs;
142 		if ((time >= m_pTimeInfo[i].time) && (time < tEnd))
143 		{
144 			mixPos = m_pTimeInfo[i].nBlock;
145 			pCurrentMixSample = pBigSampleBuffer + pMixBlock[mixPos].sampleStart;
146 			currentSampleLength = (pMixBlock[mixPos].sampleLength)<<12;
147 			currentPente = (((ymu32)pMixBlock[mixPos].replayFreq)<<12) / replayRate;
148 
149 			ymu32 len = tEnd - m_pTimeInfo[i].time;
150 			ymu32 t0 = ((time - m_pTimeInfo[i].time) * pMixBlock[mixPos].sampleLength) / len;
151 
152 			currentPos = t0 << 12;
153 			nbRepeat = m_pTimeInfo[i].nRepeat;
154 			break;
155 		}
156 	}
157 
158 	m_iMusicPosInMs = time;
159 	m_iMusicPosAccurateSample = 0;
160 }
161 
setMusicTime(ymu32 time)162 ymu32	CYmMusic::setMusicTime(ymu32 time)
163 {
164 		if (!isSeekable()) return 0;
165 		ymu32 newTime = 0;
166 
167 		if ((songType>=YM_V2) && (songType<YM_VMAX))
168 		{
169 			newTime = time;
170 			if (newTime>=getMusicTime()) newTime = 0;
171 			currentFrame = (newTime*(ymu32)playerRate)/1000;
172 		}
173 		else if ((songType>=YM_TRACKER1) && (songType<YM_TRACKERMAX))
174 		{
175 			newTime = time;
176 			if (newTime>=getMusicTime()) newTime = 0;
177 			currentFrame = (newTime*(ymu32)playerRate)/1000;
178 		}
179 		else if ((songType>=YM_MIX1) && (songType<YM_MIXMAX))
180 		{
181 			assert(m_pTimeInfo);
182 			setMixTime(time);
183 		}
184 
185 		return newTime;
186 }
187 
restart(void)188 void	CYmMusic::restart(void)
189 {
190 	setMusicTime(0);
191 	bMusicOver = YMFALSE;
192 }
193 
194 
195 
getMusicInfo(ymMusicInfo_t * pInfo)196 void	CYmMusic::getMusicInfo(ymMusicInfo_t *pInfo)
197 {
198 		if (pInfo)
199 		{
200 			pInfo->pSongName = pSongName;
201 			pInfo->pSongAuthor = pSongAuthor;
202 			pInfo->pSongComment = pSongComment;
203 			pInfo->pSongType = pSongType;
204 			pInfo->pSongPlayer = pSongPlayer;
205 
206 			pInfo->musicTimeInMs = getMusicTime();
207 			pInfo->musicTimeInSec = pInfo->musicTimeInMs / 1000;
208 		}
209 }
210 
211 
setAttrib(ymint _attrib)212 void	CYmMusic::setAttrib(ymint _attrib)
213 {
214 		attrib = _attrib;
215 }
216 
getAttrib(void)217 ymint		CYmMusic::getAttrib(void)
218 {
219 		return attrib;
220 }
221 
isSeekable(void)222 ymbool	CYmMusic::isSeekable(void)
223 {
224 		return getAttrib()&A_TIMECONTROL;
225 }
226 
setLastError(const char * pError)227 void	CYmMusic::setLastError(const char *pError)
228 {
229 		pLastError = pError;
230 }
231 
getLastError(void)232 const char *CYmMusic::getLastError(void)
233 {
234 		return pLastError;
235 }
236 
bufferClear(ymsample * pBuffer,ymint nbSample)237 void	bufferClear(ymsample *pBuffer,ymint nbSample)
238 {
239 		memset((void*)pBuffer,0,nbSample*sizeof(ymsample));
240 }
241 
update(ymsample * sampleBuffer,ymint nbSample)242 ymbool	CYmMusic::update(ymsample *sampleBuffer,ymint nbSample)
243 {
244 ymint sampleToCompute;
245 ymint	vblNbSample;
246 
247 
248 		if ((!bMusicOk) ||
249 			(bPause) ||
250 			(bMusicOver))
251 		{
252 			bufferClear(sampleBuffer,nbSample);
253 			if (bMusicOver)
254 				return YMFALSE;
255 			else
256 				return YMTRUE;
257 		}
258 
259 		if ((songType >= YM_MIX1) && (songType < YM_MIXMAX))
260 		{
261 			stDigitMix(sampleBuffer,nbSample);
262 
263 
264 		}
265 		else if ((songType >= YM_TRACKER1) && (songType<YM_TRACKERMAX))
266 		{
267 			ymTrackerUpdate(sampleBuffer,nbSample);
268 		}
269 		else
270 		{
271 			ymsample *pOut = sampleBuffer;
272 			ymint nbs = nbSample;
273 			vblNbSample = replayRate/playerRate;
274 			do
275 			{
276 				// Nb de sample � calculer avant l'appel de Player
277 				sampleToCompute = vblNbSample-innerSamplePos;
278 				// Test si la fin du buffer arrive avant la fin de sampleToCompute
279 				if (sampleToCompute>nbs) sampleToCompute = nbs;
280 				innerSamplePos += sampleToCompute;
281 				if (innerSamplePos>=vblNbSample)
282 				{
283 					player();			// Lecture de la partition (playerRate Hz)
284 					innerSamplePos -= vblNbSample;
285 				}
286 				if (sampleToCompute>0)
287 				{
288 					ymChip.update(pOut,sampleToCompute);	// YM Emulation.
289 					pOut += sampleToCompute;
290 				}
291 				nbs -= sampleToCompute;
292 			}
293 			while (nbs>0);
294 		}
295 
296 
297 		return YMTRUE;
298 }
299 
300 
301 
readYm6Effect(unsigned char * pReg,ymint code,ymint prediv,ymint count)302 void	CYmMusic::readYm6Effect(unsigned char *pReg,ymint code,ymint prediv,ymint count)
303 {
304 ymint voice;
305 ymint ndrum;
306 
307 		code = pReg[code]&0xf0;
308 		prediv = (pReg[prediv]>>5)&7;
309 		count = pReg[count];
310 
311 		if (code&0x30)
312 		{
313 			ymu32 tmpFreq;
314 			// Ici il y a un effet sur la voie:
315 
316 			voice = ((code&0x30)>>4)-1;
317 			switch (code&0xc0)
318 			{
319 				case 0x00:		// SID
320 				case 0x80:		// Sinus-SID
321 
322 					prediv = mfpPrediv[prediv];
323 					prediv *= count;
324 					tmpFreq = 0;
325 					if (prediv)
326 					{
327 						tmpFreq = 2457600L / prediv;
328 						if ((code&0xc0)==0x00)
329 							ymChip.sidStart(voice,tmpFreq,pReg[voice+8]&15);
330 						else
331 							ymChip.sidSinStart(voice,tmpFreq,pReg[voice+8]&15);
332 					}
333 					break;
334 
335 				case 0x40:		// DigiDrum
336 					ndrum = pReg[voice+8]&31;
337 					if ((ndrum>=0) && (ndrum<nbDrum))
338 					{
339 						prediv = mfpPrediv[prediv];
340 						prediv *= count;
341 						if (prediv>0)
342 						{
343 							tmpFreq = 2457600L / prediv;
344 							ymChip.drumStart(voice,pDrumTab[ndrum].pData,pDrumTab[ndrum].size,tmpFreq);
345 						}
346 					}
347 					break;
348 
349 				case 0xc0:		// Sync-Buzzer.
350 
351 					prediv = mfpPrediv[prediv];
352 					prediv *= count;
353 					tmpFreq = 0;
354 					if (prediv)
355 					{
356 						tmpFreq = 2457600L / prediv;
357 						ymChip.syncBuzzerStart(tmpFreq,pReg[voice+8]&15);
358 					}
359 					break;
360 
361 
362 			}
363 
364 		}
365 }
366 
setVolume(ymint volume)367 void	CYmMusic::setVolume(ymint volume)
368 {
369 //		ymChip.setGlobalVolume(volume);
370 }
371 
player(void)372 void	CYmMusic::player(void)
373  {
374  ymu8	*ptr;
375  ymu32 prediv;
376  ymint voice;
377  ymint ndrum;
378 
379 
380 	if (currentFrame<0) currentFrame = 0;
381 
382 	if (currentFrame>=nbFrame)
383 	{
384 		if (bLoop)
385 		{
386 			currentFrame = loopFrame;
387 			if (currentFrame < 0)
388 				currentFrame = 0;
389 			else if (currentFrame >= nbFrame)
390 				currentFrame = nbFrame - 1;
391 		}
392 		else
393 		{
394 			bMusicOver = YMTRUE;
395 			ymChip.reset();
396 			return;
397 		}
398 	}
399 
400 	ptr = pDataStream+currentFrame*streamInc;
401 
402 	for (ymint i=0;i<=10;i++)
403 		ymChip.writeRegister(i,ptr[i]);
404 
405 	ymChip.sidStop(0);
406 	ymChip.sidStop(1);
407 	ymChip.sidStop(2);
408 	ymChip.syncBuzzerStop();
409 
410 	//---------------------------------------------
411 	// Check digi-drum
412 	//---------------------------------------------
413 	if (songType == YM_V2)		// MADMAX specific !
414 	{
415 		if (ptr[13]!=0xff)
416 		{
417 			ymChip.writeRegister(11,ptr[11]);
418 			ymChip.writeRegister(12,0);
419 			ymChip.writeRegister(13,10);				// MADMAX specific !!
420 		}
421 		if (ptr[10]&0x80)					// bit 7 volume canal C pour annoncer une digi-drum madmax.
422 		{
423 			ymint	sampleNum;
424 			ymu32 sampleFrq;
425 			ymChip.writeRegister(7,ymChip.readRegister(7)|0x24)	;	// Coupe TONE + NOISE canal C.
426 			sampleNum = ptr[10]&0x7f;		// Numero du sample
427 
428 			if (ptr[12])
429 			{
430 				if (sampleNum < MAX_DIGIDRUM)
431 				{
432 					sampleFrq = (MFP_CLOCK / ptr[12]);
433 					ymChip.drumStart(	2,							// Voice C
434 										sampleAdress[sampleNum],
435 										sampleLen[sampleNum],
436 										sampleFrq);
437 				}
438 			}
439 		}
440 	}
441 	else if (songType >= YM_V3)
442 	{
443 		ymChip.writeRegister(11,ptr[11]);
444 		ymChip.writeRegister(12,ptr[12]);
445 		if (ptr[13]!=0xff)
446 		{
447 			ymChip.writeRegister(13,ptr[13]);
448 		}
449 
450 		if (songType >= YM_V5)
451 		{
452 			ymint code;
453 
454 			if (songType == YM_V6)
455 			{
456 				readYm6Effect(ptr,1,6,14);
457 				readYm6Effect(ptr,3,8,15);
458 			}
459 			else
460 			{	// YM5 effect decoding
461 
462 			//------------------------------------------------------
463 			// Sid Voice !!
464 			//------------------------------------------------------
465 				code = (ptr[1]>>4)&3;
466 				if (code!=0)
467 				{
468 					ymu32 tmpFreq;
469 					voice = code-1;
470 					prediv = mfpPrediv[(ptr[6]>>5)&7];
471 					prediv *= ptr[14];
472 					tmpFreq = 0;
473 					if (prediv)
474 					{
475 						tmpFreq = 2457600L / prediv;
476 						ymChip.sidStart(voice,tmpFreq,ptr[voice+8]&15);
477 					}
478 				}
479 
480 			//------------------------------------------------------
481 			// YM5 Digi Drum.
482 			//------------------------------------------------------
483 				code = (ptr[3]>>4)&3;
484 				if (code!=0)
485 				{	// Ici un digidrum demarre sur la voie voice.
486 					voice = code-1;
487 					ndrum = ptr[8+voice]&31;
488 					if ((ndrum>=0) && (ndrum<nbDrum))
489 					{
490 						ymu32 sampleFrq;
491 						prediv = mfpPrediv[(ptr[8]>>5)&7];
492 						prediv *= ptr[15];
493 						if (prediv)
494 						{
495 							sampleFrq = MFP_CLOCK / prediv;
496 							ymChip.drumStart(voice,pDrumTab[ndrum].pData,pDrumTab[ndrum].size,sampleFrq);
497 						}
498 					}
499 				}
500 			}
501 		}
502 	}
503 	currentFrame++;
504  }
505 
506 /*
507 
508 	x x x x x x x x	r0
509 	0 0 0 0 x x x x	r1		// Special FX 1a
510 	x x x x x x x x	r2
511 	0 0 0 0 x x x x r3		// Special FX 2a
512 	x x x x x x x x r4
513 	0 0 0 0 x x x x r5
514 	0 0 0 x x x x x r6		// Special FX 1b
515 	0 0 x x x x x x r7
516 	0 0 0 x x x x x r8		// Special FX 2b
517 	0 0 0 x x x x x r9
518 	0 0 0 x x x x x r10
519 	x x x x x x x x r11
520 	x x x x x x x x r12
521 	0 0 0 0 x x x x r13
522 	0 0 0 0 0 0 0 0 r14		// Special FX 1c
523 	0 0 0 0 0 0 0 0 r15		// Special FX 2c
524 
525 
526   Special Fx ?a
527 	0 0 0 0	: No special FX running
528 	0 0 0 1 : Sid Voice A
529 	0 0 1 0 : Sid Voice B
530 	0 0 1 1 : Sid Voice C
531 	0 1 0 0 : Extended Fx voice A
532 	0 1 0 1 : Digidrum voice A
533 	0 1 1 0 : Digidrum voice B
534 	0 1 1 1 : Digidrum voice C
535 	1 0 0 0 : Extended Fx voice B
536 	1 0 0 1 : Sinus SID voice A
537 	1 0 1 0 : Sinus SID voice B
538 	1 0 1 1 : Sinus SID voice C
539 	1 1 0 0 : Extended Fx voice C
540 	1 1 0 1 : Sync Buzzer voice A
541 	1 1 1 0 : Sync Buzzer voice B
542 	1 1 1 1 : Sync Buzzer voice C
543 
544 
545 
546 */
547 
computeTimeInfo(void)548 void	CYmMusic::computeTimeInfo(void)
549 {
550 
551 	assert(NULL == m_pTimeInfo);
552 
553 	//-------------------------------------------
554 	// Compute nb of mixblock
555 	//-------------------------------------------
556 	m_nbTimeKey = 0;
557 	ymint i;
558 	for (i=0;i<nbMixBlock;i++)
559 	{
560 		if (pMixBlock[i].nbRepeat >= 32)
561 			pMixBlock[i].nbRepeat = 32;
562 
563 		m_nbTimeKey += pMixBlock[i].nbRepeat;
564 	}
565 
566 	//-------------------------------------------
567 	// Parse all mixblock keys
568 	//-------------------------------------------
569 	m_pTimeInfo = (TimeKey*)malloc(sizeof(TimeKey) * m_nbTimeKey);
570 	TimeKey *pKey = m_pTimeInfo;
571 	ymu32 time = 0;
572 
573 	for (i=0;i<nbMixBlock;i++)
574 	{
575 		for (ymint j=0;j<pMixBlock[i].nbRepeat;j++)
576 		{
577 			pKey->time = time;
578 			pKey->nRepeat = pMixBlock[i].nbRepeat - j;
579 			pKey->nBlock = i;
580 			pKey++;
581 
582 			time += (pMixBlock[i].sampleLength * 1000) / pMixBlock[i].replayFreq;
583 		}
584 	}
585 	m_musicLenInMs = time;
586 
587 }
588 
readNextBlockInfo(void)589 void	CYmMusic::readNextBlockInfo(void)
590 {
591 	nbRepeat--;
592 	if (nbRepeat<=0)
593 	{
594 		mixPos++;
595 		if (mixPos >= nbMixBlock)
596 		{
597 			mixPos = 0;
598 			if (!bLoop) bMusicOver = YMTRUE;
599 
600 			m_iMusicPosAccurateSample = 0;
601 			m_iMusicPosInMs = 0;
602 		}
603 		nbRepeat = pMixBlock[mixPos].nbRepeat;
604 	}
605 	pCurrentMixSample = pBigSampleBuffer + pMixBlock[mixPos].sampleStart;
606 	currentSampleLength = (pMixBlock[mixPos].sampleLength)<<12;
607 	currentPente = (((ymu32)pMixBlock[mixPos].replayFreq)<<12) / replayRate;
608 	currentPos &= ((1<<12)-1);
609 }
610 
stDigitMix(ymsample * pWrite16,ymint nbs)611 void	CYmMusic::stDigitMix(ymsample *pWrite16,ymint nbs)
612 {
613 
614 
615 		if (bMusicOver) return;
616 
617 		if (mixPos == -1)
618 		{
619 			nbRepeat = -1;
620 			readNextBlockInfo();
621 		}
622 
623 		m_iMusicPosAccurateSample += nbs * 1000;
624 		m_iMusicPosInMs += ((m_iMusicPosAccurateSample) / (replayRate));
625 		m_iMusicPosAccurateSample %= (replayRate);
626 
627 		if (nbs) do
628 		{
629 
630 			ymint sa = (ymint)(ymsample)(pCurrentMixSample[currentPos>>12]<<8);
631 #ifdef _LINEAR_OVRS
632 			ymint sb = sa;
633 			if ((currentPos>>12)<((currentSampleLength>>12)-1))
634 				sb = (ymint)(ymsample)(pCurrentMixSample[(currentPos>>12)+1]<<8);
635 			ymint frac = currentPos&((1<<12)-1);
636 			sa += (((sb-sa)*frac)>>12);
637 #endif
638 			*pWrite16++ = sa;
639 
640 			currentPos += currentPente;
641 			if (currentPos>=currentSampleLength)
642 			{
643 				readNextBlockInfo();
644 				if (bMusicOver) return;
645 			}
646 		}
647 		while (--nbs);
648 }
649 
ymTrackerDesInterleave(void)650 void	CYmMusic::ymTrackerDesInterleave(void)
651 {
652 unsigned char *a0,*a1,*a2;
653 unsigned char *pNewBuffer;
654 ymint	step;
655 ymu32 n1,n2;
656 
657 
658 		if (attrib&A_STREAMINTERLEAVED)
659 		{
660 			a0 = pDataStream;
661 			ymint size = sizeof(ymTrackerLine_t)*nbVoice*nbFrame;
662 			pNewBuffer = (unsigned char*)malloc(size);
663 			step = sizeof(ymTrackerLine_t)*nbVoice;
664 			n1 = step;
665 			a2 = pNewBuffer;
666 			do
667 			{
668 				n2 = nbFrame;
669 				a1 = a2;
670 				do
671 				{
672 					*a1 = *a0++;
673 					a1 += step;
674 				}
675 				while (--n2);
676 				a2++;
677 			}
678 			while (--n1);
679 			memcpy(pDataStream,pNewBuffer,size);
680 			free(pNewBuffer);
681 			attrib &= (~A_STREAMINTERLEAVED);
682 		}
683 }
684 
685 
ymTrackerInit(ymint volMaxPercent)686 void	CYmMusic::ymTrackerInit(ymint volMaxPercent)
687 {
688 ymint i,s;
689 ymint vol;
690 ymint scale;
691 ymsample *pTab;
692 
693 
694 
695 		for (i=0;i<MAX_VOICE;i++)
696 			ymTrackerVoice[i].bRunning = 0;
697 
698 		ymTrackerNbSampleBefore = 0;
699 
700 		scale = (256*volMaxPercent) / (nbVoice*100);
701 		pTab = ymTrackerVolumeTable;
702 
703 		// Construit la table de volume.
704 		for (vol=0;vol<64;vol++)
705 		{
706 			for (s=-128;s<128;s++)
707 			{
708 				*pTab++ = (s*(ymint)scale*vol)/64;
709 			}
710 		}
711 
712 		// Des-interleave si necessaire.
713 		ymTrackerDesInterleave();
714 
715 }
716 
717 
ymTrackerPlayer(ymTrackerVoice_t * pVoice)718 void	CYmMusic::ymTrackerPlayer(ymTrackerVoice_t *pVoice)
719 {
720 ymint i;
721 ymTrackerLine_t *pLine;
722 
723 
724 		pLine = (ymTrackerLine_t*)pDataStream;
725 		pLine += (currentFrame*nbVoice);
726 	  	for (i=0;i<nbVoice;i++)
727 		{
728 			ymint n;
729 			pVoice[i].sampleFreq = ((ymint)pLine->freqHigh<<8) | pLine->freqLow;
730 			if (pVoice[i].sampleFreq)
731 			{
732 				pVoice[i].sampleVolume = pLine->volume&63;
733 				pVoice[i].bLoop = (pLine->volume&0x40);
734 				n = pLine->noteOn;
735 				if (n != 0xff)		// Note ON.
736 				{
737 					if ((n>=0) && (n<nbDrum))
738 					{
739 						pVoice[i].bRunning = 1;
740 						pVoice[i].pSample = pDrumTab[n].pData;
741 						pVoice[i].sampleSize = pDrumTab[n].size;
742 						pVoice[i].repLen = pDrumTab[n].repLen;
743 						pVoice[i].samplePos = 0;
744 					}
745 				}
746 			}
747 			else
748 			{
749 				pVoice[i].bRunning = 0;
750 			}
751 			pLine++;
752 		}
753 
754 		currentFrame++;
755 		if (currentFrame >= nbFrame)
756 		{
757 			if (!bLoop)
758 			{
759 				bMusicOver = YMTRUE;
760 			}
761 			currentFrame = 0;
762 		}
763 }
764 
765 
ymTrackerVoiceAdd(ymTrackerVoice_t * pVoice,ymsample * pBuffer,ymint nbs)766 void	CYmMusic::ymTrackerVoiceAdd(ymTrackerVoice_t *pVoice,ymsample *pBuffer,ymint nbs)
767 {
768 ymsample *pVolumeTab;
769 ymu8 *pSample;
770 ymu32 samplePos;
771 ymu32 sampleEnd;
772 ymu32 sampleInc;
773 ymu32 repLen;
774 double	step;
775 
776 
777 		if (!(pVoice->bRunning)) return;
778 
779 		pVolumeTab = &ymTrackerVolumeTable[256*(pVoice->sampleVolume&63)];
780 		pSample = pVoice->pSample;
781 		samplePos = pVoice->samplePos;
782 
783 		step = (double)(pVoice->sampleFreq<<YMTPREC);
784 		step *= (double)(1<<ymTrackerFreqShift);
785 		step /= (double)replayRate;
786 		sampleInc = (ymu32)step;
787 
788 		sampleEnd = (pVoice->sampleSize<<YMTPREC);
789 		repLen = (pVoice->repLen<<YMTPREC);
790 		if (nbs>0) do
791 		{
792 			ymint va = pVolumeTab[pSample[samplePos>>YMTPREC]];
793 #ifdef _LINEAR_OVRS
794 			ymint vb = va;
795 			if (samplePos < (sampleEnd-(1<<YMTPREC)))
796 				vb = pVolumeTab[pSample[(samplePos>>YMTPREC)+1]];
797 
798 			ymint frac = samplePos & ((1<<YMTPREC)-1);
799 			va += (((vb-va)*frac)>>YMTPREC);
800 #endif
801 			(*pBuffer++) += va;
802 
803 			samplePos += sampleInc;
804 			if (samplePos>=sampleEnd)
805 			{
806 				if (pVoice->bLoop)
807 				{
808 					samplePos -= repLen;
809 				}
810 				else
811 				{
812 					pVoice->bRunning = 0;
813 					return;
814 				}
815 			}
816 		}
817 		while (--nbs);
818 		pVoice->samplePos = samplePos;
819 }
820 
ymTrackerUpdate(ymsample * pBuffer,ymint nbSample)821 void	CYmMusic::ymTrackerUpdate(ymsample *pBuffer,ymint nbSample)
822 {
823 ymint i;
824 ymint _nbs;
825 
826 		// Clear les buffers.
827 		memset(pBuffer,0,sizeof(ymsample)*nbSample);
828 		if (bMusicOver) return;
829 
830 		do
831 		{
832 			if (ymTrackerNbSampleBefore == 0)
833 			{
834 				// Lit la partition ymTracker
835 				ymTrackerPlayer(ymTrackerVoice);
836 				if (bMusicOver) return;
837 				ymTrackerNbSampleBefore = replayRate / playerRate;
838 			}
839 			_nbs = ymTrackerNbSampleBefore;		// nb avant playerUpdate.
840 			if (_nbs>nbSample) _nbs = nbSample;
841 			ymTrackerNbSampleBefore -= _nbs;
842 			if (_nbs>0)
843 			{
844 				// Genere les samples.
845 				for (i=0;i<nbVoice;i++)
846 				{
847 					ymTrackerVoiceAdd(&ymTrackerVoice[i],pBuffer,_nbs);
848 				}
849 				pBuffer += _nbs;
850 				nbSample -= _nbs;
851 			}
852 		}
853 		while (nbSample>0);
854 }
855