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