20 (AllocSysMemory(0, size, NULL))
25#define Period2Freq(period) (3579545 / (period))
26#define min(a, b) (((a) < (b)) ? (a) : (b))
28#define AHXOI_OVERSAMPLING 1
31 0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253, 255,
32 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24,
33 0, -24, -49, -74, -97, -120, -141, -161, -180, -197, -212, -224, -235, -244, -250, -253, -255,
34 -253, -250, -244, -235, -224, -212, -197, -180, -161, -141, -120, -97, -74, -49, -24};
37 0x0000, 0x0D60, 0x0CA0, 0x0BE8, 0x0B40, 0x0A98, 0x0A00, 0x0970,
38 0x08E8, 0x0868, 0x07F0, 0x0780, 0x0714, 0x06B0, 0x0650, 0x05F4,
39 0x05A0, 0x054C, 0x0500, 0x04B8, 0x0474, 0x0434, 0x03F8, 0x03C0,
40 0x038A, 0x0358, 0x0328, 0x02FA, 0x02D0, 0x02A6, 0x0280, 0x025C,
41 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C5, 0x01AC, 0x0194, 0x017D,
42 0x0168, 0x0153, 0x0140, 0x012E, 0x011D, 0x010D, 0x00FE, 0x00F0,
43 0x00E2, 0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00AA, 0x00A0, 0x0097,
44 0x008F, 0x0087, 0x007F, 0x0078, 0x0071};
46int Offsets[] = {0x00, 0x04, 0x04 + 0x08, 0x04 + 0x08 + 0x10, 0x04 + 0x08 + 0x10 + 0x20, 0x04 + 0x08 + 0x10 + 0x20 + 0x40};
50int VolumeTable[65][256];
51char VoiceBuffer[0x281];
60short insrument_count = 0;
61short position_count = 0;
64int pos[4] = {0, 0, 0, 0};
67int StepWaitFrames, GetNewPosition, SongEndReached, TimingValue;
72int NoteNr, PosJumpNote;
80#define Frequency 48000
88void GenerateTriangle(
char *Buffer,
int Len)
98 for (ecx = 0; ecx < d5; ecx++) {
105 for (ecx = 0; ecx < d5 - 1; ecx++) {
111 for (ecx = 0; ecx < d5 * 2; ecx++) {
120void GenerateSquare(
char *Buffer)
124 for (ebx = 1; ebx <= 0x20; ebx++) {
125 for (ecx = 0; ecx < (0x40 - ebx) * 2; ecx++)
127 for (ecx = 0; ecx < ebx * 2; ecx++)
132void GenerateSawtooth(
char *Buffer,
int Len)
136 int ebx = 256 / (Len - 1), eax = -128;
137 for (ecx = 0; ecx < Len; ecx++) {
143void GenerateWhiteNoise(
char *Buffer,
int Len)
145 unsigned int Seed = 0x41595321;
149 *Buffer = (char)(Seed & 0xff);
150 else if (!(Seed & 0xffff))
156 unsigned int tmp = Seed;
161 unsigned int tmp2 = tmp = Seed;
175void AHXVoice_Init(
struct AHXVoice *pVoice)
177 memset(pVoice, 0,
sizeof(
struct AHXVoice));
178 memset(pVoice->VoiceBuffer, 0, 0x281);
180 pVoice->TrackMasterVolume = 0x40;
183void AHXVoice_CalcADSR(
struct AHXVoice *pVoice)
185 pVoice->ADSR.aFrames = pVoice->Instrument->Envelope.aFrames;
186 pVoice->ADSR.aVolume = pVoice->Instrument->Envelope.aVolume * 256 / pVoice->ADSR.aFrames;
187 pVoice->ADSR.dFrames = pVoice->Instrument->Envelope.dFrames;
188 pVoice->ADSR.dVolume = (pVoice->Instrument->Envelope.dVolume - pVoice->Instrument->Envelope.aVolume) * 256 / pVoice->ADSR.dFrames;
189 pVoice->ADSR.sFrames = pVoice->Instrument->Envelope.sFrames;
190 pVoice->ADSR.rFrames = pVoice->Instrument->Envelope.rFrames;
191 pVoice->ADSR.rVolume = (pVoice->Instrument->Envelope.rVolume - pVoice->Instrument->Envelope.dVolume) * 256 / pVoice->ADSR.rFrames;
197#pragma warning(disable : 4309 4305)
204 if (*x > (
int)((u32)(127) << FIXEDPOINT)) {
205 *x = (int)((u32)(127) << FIXEDPOINT);
208 if (*x < (
int)((u32)(-128) << FIXEDPOINT)) {
209 *x = (int)((u32)(-128) << FIXEDPOINT);
214void GenerateFilterWaveforms(
char *Buffer,
char *Low,
char *High)
216 const int LengthTable[] = {3, 7, 0xf, 0x1f, 0x3f, 0x7f, 3, 7, 0xf, 0x1f, 0x3f, 0x7f,
217 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
218 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
220 int temp, freq, waves, i, highint, midint, lowint;
222 for (temp = 0, freq = 8; temp < 31; temp++, freq += 3) {
225 int v125 = (1 << FIXEDPOINT) + ((1 << FIXEDPOINT) / 4);
226 int freint = ((freq * v125) / 100);
227 for (waves = 0; waves < 6 + 6 + 0x20 + 1; waves++) {
233 for (i = 0; i <= LengthTable[waves]; i++) {
241 highint = (((int)(a0[i])) << FIXEDPOINT) - midint - lowint;
243 midint += (highint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
245 lowint += (midint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
248 for (i = 0; i <= LengthTable[waves]; i++) {
258 highint = (((int)(a0[i])) << FIXEDPOINT) - midint - lowint;
260 midint += (highint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
262 lowint += (midint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
265 char low_ = (lowint >> FIXEDPOINT);
266 char high_ = (highint >> FIXEDPOINT);
271 a0 += LengthTable[waves] + 1;
277int AHXOutput_SetOption(
int Option,
int Value)
283 for (
int i = 0; i < 65; i++) {
284 for (
int j = -128; j < 128; j++) {
285 VolumeTable[i][j + 128] = (int)(i * j * Value) / 64;
299 WaveformTab[0] = Waves->Triangle04;
300 WaveformTab[1] = Waves->Sawtooth04;
301 WaveformTab[3] = Waves->WhiteNoiseBig;
303 GenerateSawtooth(Waves->Sawtooth04, 0x04);
304 GenerateSawtooth(Waves->Sawtooth08, 0x08);
305 GenerateSawtooth(Waves->Sawtooth10, 0x10);
306 GenerateSawtooth(Waves->Sawtooth20, 0x20);
307 GenerateSawtooth(Waves->Sawtooth40, 0x40);
308 GenerateSawtooth(Waves->Sawtooth80, 0x80);
309 GenerateTriangle(Waves->Triangle04, 0x04);
310 GenerateTriangle(Waves->Triangle08, 0x08);
311 GenerateTriangle(Waves->Triangle10, 0x10);
312 GenerateTriangle(Waves->Triangle20, 0x20);
313 GenerateTriangle(Waves->Triangle40, 0x40);
314 GenerateTriangle(Waves->Triangle80, 0x80);
315 GenerateSquare(Waves->Squares);
316 GenerateWhiteNoise(Waves->WhiteNoiseBig, 0x280 * 3);
317 GenerateFilterWaveforms(Waves->Triangle04, Waves->LowPasses, Waves->HighPasses);
319 MixingBuffer = (
int *)malloc(
sizeof(
int) * (MixLen * Frequency / Hz));
321 AHXOutput_SetOption(AHXOF_BOOST, Boost + 1);
324void AHXPlayer_FreeMem()
329 for (i = 1; i < Song.InstrumentNr + 1; i++) {
330 free(Instruments[i].PList.Entries);
331 free(Instruments[i].Name);
335 for (i = 0; i < Song.TrackNr + 1; i++) {
345int AHXPlayer_LoadSongBuffer(
void *Buffer,
int Len)
347 int SongLength = Len;
349 unsigned char *SongBuffer = (
unsigned char *)Buffer;
350 unsigned char *SBPtr = &SongBuffer[14];
355 if (SongLength < 14 || SongLength == 65536)
358 if (SongBuffer[0] !=
'T' && SongBuffer[1] !=
'H' && SongBuffer[2] !=
'X')
360 Song.Revision = SongBuffer[3];
361 if (Song.Revision > 1)
366 NamePtr = (
char *)&SongBuffer[(SongBuffer[4] << 8) | SongBuffer[5]];
367 Song.Name = (
char *)malloc(strlen(NamePtr) + 1);
368 strcpy(Song.Name, NamePtr);
369 NamePtr += strlen(NamePtr) + 1;
370 Song.SpeedMultiplier = ((SongBuffer[6] >> 5) & 3) + 1;
372 Song.PositionNr = ((SongBuffer[6] & 0xf) << 8) | SongBuffer[7];
373 Song.Restart = (SongBuffer[8] << 8) | SongBuffer[9];
374 Song.TrackLength = SongBuffer[10];
375 Song.TrackNr = SongBuffer[11];
376 Song.InstrumentNr = SongBuffer[12];
377 Song.SubsongNr = SongBuffer[13];
380 Song.Subsongs = (
int *)malloc(
sizeof(
int) * Song.SubsongNr);
382 printf(
"name length = %d\n", strlen(NamePtr) + 1);
383 printf(
"playing: %s\n", NamePtr);
384 printf(
"subsongs = %d\n", Song.SubsongNr);
385 printf(
"Positions = %d\n", Song.PositionNr);
386 printf(
"Tracks = %d\n", (MaxTrack + 1));
388 for (i = 0; i < Song.SubsongNr; i++) {
389 if (SBPtr - SongBuffer > SongLength)
391 Song.Subsongs[i] = (SBPtr[0] << 8) | SBPtr[1];
397 for (i = 0; i < Song.PositionNr; i++) {
398 for (j = 0; j < 4; j++) {
399 if (SBPtr - SongBuffer > SongLength)
401 Positions[i].Track[j] = *SBPtr++;
402 Positions[i].Transpose[j] = *(
signed char *)SBPtr++;
407 MaxTrack = Song.TrackNr;
408 Tracks = (
struct AHXStep **)malloc(
sizeof(
struct AHXStep) * (MaxTrack + 1));
409 for (i = 0; i < MaxTrack + 1; i++) {
410 Tracks[i] = (
struct AHXStep *)malloc(
sizeof(
struct AHXStep) * Song.TrackLength);
411 if ((SongBuffer[6] & 0x80) == 0x80 && i == 0) {
412 memset(Tracks[i], 0, Song.TrackLength *
sizeof(
struct AHXStep));
415 for (j = 0; j < Song.TrackLength; j++) {
416 if (SBPtr - SongBuffer > SongLength)
418 Tracks[i][j].Note = (SBPtr[0] >> 2) & 0x3f;
419 Tracks[i][j].Instrument = ((SBPtr[0] & 0x3) << 4) | (SBPtr[1] >> 4);
420 Tracks[i][j].FX = SBPtr[1] & 0xf;
421 Tracks[i][j].FXParam = SBPtr[2];
428 for (i = 1; i < Song.InstrumentNr + 1; i++) {
429 Instruments[i].Name = (
char *)malloc(strlen(NamePtr) + 1);
430 strcpy(Instruments[i].Name, NamePtr);
431 NamePtr += strlen(NamePtr) + 1;
432 if (SBPtr - SongBuffer > SongLength)
434 Instruments[i].Volume = SBPtr[0];
435 Instruments[i].FilterSpeed = ((SBPtr[1] >> 3) & 0x1f) | ((SBPtr[12] >> 2) & 0x20);
436 Instruments[i].WaveLength = SBPtr[1] & 0x7;
437 Instruments[i].Envelope.aFrames = SBPtr[2];
438 Instruments[i].Envelope.aVolume = SBPtr[3];
439 Instruments[i].Envelope.dFrames = SBPtr[4];
440 Instruments[i].Envelope.dVolume = SBPtr[5];
441 Instruments[i].Envelope.sFrames = SBPtr[6];
442 Instruments[i].Envelope.rFrames = SBPtr[7];
443 Instruments[i].Envelope.rVolume = SBPtr[8];
444 Instruments[i].FilterLowerLimit = SBPtr[12] & 0x7f;
445 Instruments[i].VibratoDelay = SBPtr[13];
446 Instruments[i].HardCutReleaseFrames = (SBPtr[14] >> 4) & 7;
447 Instruments[i].HardCutRelease = SBPtr[14] & 0x80 ? 1 : 0;
448 Instruments[i].VibratoDepth = SBPtr[14] & 0xf;
449 Instruments[i].VibratoSpeed = SBPtr[15];
450 Instruments[i].SquareLowerLimit = SBPtr[16];
451 Instruments[i].SquareUpperLimit = SBPtr[17];
452 Instruments[i].SquareSpeed = SBPtr[18];
453 Instruments[i].FilterUpperLimit = SBPtr[19] & 0x3f;
454 Instruments[i].PList.Speed = SBPtr[20];
455 Instruments[i].PList.Length = SBPtr[21];
458 for (j = 0; j < Instruments[i].PList.Length; j++) {
459 if (SBPtr - SongBuffer > SongLength)
461 Instruments[i].PList.Entries[j].FX[1] = (SBPtr[0] >> 5) & 7;
462 Instruments[i].PList.Entries[j].FX[0] = (SBPtr[0] >> 2) & 7;
463 Instruments[i].PList.Entries[j].Waveform = ((SBPtr[0] << 1) & 6) | (SBPtr[1] >> 7);
464 Instruments[i].PList.Entries[j].Fixed = (SBPtr[1] >> 6) & 1;
465 Instruments[i].PList.Entries[j].Note = SBPtr[1] & 0x3f;
466 Instruments[i].PList.Entries[j].FXParam[0] = SBPtr[2];
467 Instruments[i].PList.Entries[j].FXParam[1] = SBPtr[3];
471 return Song.SubsongNr;
475int AHXPlayer_LoadSong(
char *Filename)
479 unsigned char SongBuffer[65536];
480 f = fopen(Filename,
"rb");
483 SongLength = fread(SongBuffer, 1, 65536, f);
485 return AHXPlayer_LoadSongBuffer(SongBuffer, SongLength);
489int AHXPlayer_InitSubsong(
int Nr)
493 if (Nr > Song.SubsongNr)
499 PosNr = Song.Subsongs[Nr - 1];
505 NoteNr = PosJumpNote = 0;
510 TimingValue = PlayingTime = 0;
512 for (v = 0; v < 4; v++) {
513 AHXVoice_Init(&Voices[v]);
519void AHXPlayer_NextPosition()
522 if (PosNr == Song.PositionNr)
528void AHXPlayer_PrevPosition()
537void AHXPlayer_ProcessStep(
int v)
539 int Note, Instrument, FX, FXParam, SquareLower, SquareUpper, d3, d4, d6, Neue, Alte, i;
541 if (!Voices[v].TrackOn)
543 Voices[v].VolumeSlideUp = Voices[v].VolumeSlideDown = 0;
545 Note = Tracks[Positions[PosNr].Track[v]][NoteNr].Note;
546 Instrument = Tracks[Positions[PosNr].Track[v]][NoteNr].Instrument;
547 FX = Tracks[Positions[PosNr].Track[v]][NoteNr].FX;
548 FXParam = Tracks[Positions[PosNr].Track[v]][NoteNr].FXParam;
552 if ((FXParam & 0xf) > 0 && (FXParam & 0xf) <= 9)
553 PosJump = FXParam & 0xf;
557 Voices[v].VolumeSlideDown = FXParam & 0x0f;
558 Voices[v].VolumeSlideUp = FXParam >> 4;
561 PosJump = PosJump * 100 + (FXParam & 0x0f) + (FXParam >> 4) * 10;
566 PosJumpNote = (FXParam & 0x0f) + (FXParam >> 4) * 10;
567 if (PosJumpNote > Song.TrackLength)
572 switch (FXParam >> 4) {
574 if ((FXParam & 0x0f) < Tempo) {
575 Voices[v].NoteCutWait = FXParam & 0x0f;
576 if (Voices[v].NoteCutWait) {
577 Voices[v].NoteCutOn = 1;
578 Voices[v].HardCutRelease = 0;
583 if (Voices[v].NoteDelayOn) {
584 Voices[v].NoteDelayOn = 0;
586 if ((FXParam & 0x0f) < Tempo) {
587 Voices[v].NoteDelayWait = FXParam & 0x0f;
588 if (Voices[v].NoteDelayWait) {
589 Voices[v].NoteDelayOn = 1;
602 Voices[v].PerfSubVolume = 0x40;
603 Voices[v].PeriodSlideSpeed = Voices[v].PeriodSlidePeriod = Voices[v].PeriodSlideLimit = 0;
604 Voices[v].ADSRVolume = 0;
605 Voices[v].Instrument = &Instruments[Instrument];
606 AHXVoice_CalcADSR(&Voices[v]);
608 Voices[v].WaveLength = Voices[v].Instrument->WaveLength;
609 Voices[v].NoteMaxVolume = Voices[v].Instrument->Volume;
611 Voices[v].VibratoCurrent = 0;
612 Voices[v].VibratoDelay = Voices[v].Instrument->VibratoDelay;
613 Voices[v].VibratoDepth = Voices[v].Instrument->VibratoDepth;
614 Voices[v].VibratoSpeed = Voices[v].Instrument->VibratoSpeed;
615 Voices[v].VibratoPeriod = 0;
617 Voices[v].HardCutRelease = Voices[v].Instrument->HardCutRelease;
618 Voices[v].HardCut = Voices[v].Instrument->HardCutReleaseFrames;
620 Voices[v].IgnoreSquare = Voices[v].SquareSlidingIn = 0;
621 Voices[v].SquareWait = Voices[v].SquareOn = 0;
622 SquareLower = Voices[v].Instrument->SquareLowerLimit >> (5 - Voices[v].WaveLength);
623 SquareUpper = Voices[v].Instrument->SquareUpperLimit >> (5 - Voices[v].WaveLength);
624 if (SquareUpper < SquareLower) {
626 SquareUpper = SquareLower;
629 Voices[v].SquareUpperLimit = SquareUpper;
630 Voices[v].SquareLowerLimit = SquareLower;
632 Voices[v].IgnoreFilter = Voices[v].FilterWait = Voices[v].FilterOn = 0;
633 Voices[v].FilterSlidingIn = 0;
634 d6 = Voices[v].Instrument->FilterSpeed;
635 d3 = Voices[v].Instrument->FilterLowerLimit;
636 d4 = Voices[v].Instrument->FilterUpperLimit;
641 Voices[v].FilterSpeed = d6;
649 Voices[v].FilterUpperLimit = d4;
650 Voices[v].FilterLowerLimit = d3;
651 Voices[v].FilterPos = 32;
653 Voices[v].PerfWait = Voices[v].PerfCurrent = 0;
654 Voices[v].PerfSpeed = Voices[v].Instrument->PList.Speed;
655 Voices[v].PerfList = &Voices[v].Instrument->PList;
658 Voices[v].PeriodSlideOn = 0;
664 Voices[v].SquarePos = FXParam >> (5 - Voices[v].WaveLength);
665 Voices[v].PlantSquare = 1;
666 Voices[v].IgnoreSquare = 1;
671 Voices[v].PeriodSlideSpeed = FXParam;
673 Neue = PeriodTable[Note];
674 Alte = PeriodTable[Voices[v].TrackPeriod];
676 Neue = Alte + Voices[v].PeriodSlidePeriod;
678 Voices[v].PeriodSlideLimit = -Alte;
680 Voices[v].PeriodSlideOn = 1;
681 Voices[v].PeriodSlideWithLimit = 1;
687 Voices[v].TrackPeriod = Note;
688 Voices[v].PlantPeriod = 1;
693 Voices[v].PeriodSlideSpeed = -FXParam;
694 Voices[v].PeriodSlideOn = 1;
695 Voices[v].PeriodSlideWithLimit = 0;
698 Voices[v].PeriodSlideSpeed = FXParam;
699 Voices[v].PeriodSlideOn = 1;
700 Voices[v].PeriodSlideWithLimit = 0;
704 Voices[v].NoteMaxVolume = FXParam;
708 for (i = 0; i < 4; i++)
709 Voices[i].TrackMasterVolume = FXParam;
711 FXParam -= 0xa0 - 0x50;
713 Voices[v].TrackMasterVolume = FXParam;
718 switch (FXParam >> 4) {
720 Voices[v].PeriodSlidePeriod = -(FXParam & 0x0f);
721 Voices[v].PlantPeriod = 1;
724 Voices[v].PeriodSlidePeriod = FXParam & 0x0f;
725 Voices[v].PlantPeriod = 1;
728 Voices[v].VibratoDepth = FXParam & 0x0f;
731 Voices[v].NoteMaxVolume += FXParam & 0x0f;
732 if (Voices[v].NoteMaxVolume > 0x40)
733 Voices[v].NoteMaxVolume = 0x40;
736 Voices[v].NoteMaxVolume -= FXParam & 0x0f;
737 if (Voices[v].NoteMaxVolume < 0)
738 Voices[v].NoteMaxVolume = 0;
745void AHXPlayer_PListCommandParse(
int v,
int FX,
int FXParam)
749 if (Song.Revision > 0 && FXParam != 0) {
750 if (Voices[v].IgnoreFilter) {
751 Voices[v].FilterPos = Voices[v].IgnoreFilter;
752 Voices[v].IgnoreFilter = 0;
754 Voices[v].FilterPos = FXParam;
755 Voices[v].NewWaveform = 1;
759 Voices[v].PeriodPerfSlideSpeed = FXParam;
760 Voices[v].PeriodPerfSlideOn = 1;
763 Voices[v].PeriodPerfSlideSpeed = -FXParam;
764 Voices[v].PeriodPerfSlideOn = 1;
767 if (!Voices[v].IgnoreSquare) {
768 Voices[v].SquarePos = FXParam >> (5 - Voices[v].WaveLength);
770 Voices[v].IgnoreSquare = 0;
773 if (Song.Revision == 0 || FXParam == 0) {
774 Voices[v].SquareInit = (Voices[v].SquareOn ^= 1);
775 Voices[v].SquareSign = 1;
777 if (FXParam & 0x0f) {
778 Voices[v].SquareInit = (Voices[v].SquareOn ^= 1);
779 Voices[v].SquareSign = 1;
780 if ((FXParam & 0x0f) == 0x0f)
781 Voices[v].SquareSign = -1;
783 if (FXParam & 0xf0) {
784 Voices[v].FilterInit = (Voices[v].FilterOn ^= 1);
785 Voices[v].FilterSign = 1;
786 if ((FXParam & 0xf0) == 0xf0)
787 Voices[v].FilterSign = -1;
792 Voices[v].PerfCurrent = FXParam;
795 if (FXParam > 0x40) {
796 if ((FXParam -= 0x50) >= 0) {
798 Voices[v].PerfSubVolume = FXParam;
799 else if ((FXParam -= 0xa0 - 0x50) >= 0)
801 Voices[v].TrackMasterVolume = FXParam;
804 Voices[v].NoteMaxVolume = FXParam;
807 Voices[v].PerfSpeed = Voices[v].PerfWait = FXParam;
812void AHXPlayer_ProcessFrame(
int v)
817 if (!Voices[v].TrackOn)
820 if (Voices[v].NoteDelayOn) {
821 if (Voices[v].NoteDelayWait <= 0)
822 AHXPlayer_ProcessStep(v);
824 Voices[v].NoteDelayWait--;
826 if (Voices[v].HardCut) {
828 if (NoteNr + 1 < Song.TrackLength)
829 NextInstrument = Tracks[Voices[v].Track][NoteNr + 1].Instrument;
831 NextInstrument = Tracks[Voices[v].NextTrack][0].Instrument;
832 if (NextInstrument) {
833 int d1 = Tempo - Voices[v].HardCut;
836 if (!Voices[v].NoteCutOn) {
837 Voices[v].NoteCutOn = 1;
838 Voices[v].NoteCutWait = d1;
839 Voices[v].HardCutReleaseF = -(d1 - Tempo);
841 Voices[v].HardCut = 0;
844 if (Voices[v].NoteCutOn) {
845 if (Voices[v].NoteCutWait <= 0) {
846 Voices[v].NoteCutOn = 0;
847 if (Voices[v].HardCutRelease) {
848 Voices[v].ADSR.rVolume = -(Voices[v].ADSRVolume - (Voices[v].Instrument->Envelope.rVolume << 8)) / Voices[v].HardCutReleaseF;
849 Voices[v].ADSR.rFrames = Voices[v].HardCutReleaseF;
850 Voices[v].ADSR.aFrames = Voices[v].ADSR.dFrames = Voices[v].ADSR.sFrames = 0;
852 Voices[v].NoteMaxVolume = 0;
854 Voices[v].NoteCutWait--;
857 if (Voices[v].ADSR.aFrames) {
858 Voices[v].ADSRVolume += Voices[v].ADSR.aVolume;
859 if (--Voices[v].ADSR.aFrames <= 0)
860 Voices[v].ADSRVolume = Voices[v].Instrument->Envelope.aVolume << 8;
861 }
else if (Voices[v].ADSR.dFrames) {
862 Voices[v].ADSRVolume += Voices[v].ADSR.dVolume;
863 if (--Voices[v].ADSR.dFrames <= 0)
864 Voices[v].ADSRVolume = Voices[v].Instrument->Envelope.dVolume << 8;
865 }
else if (Voices[v].ADSR.sFrames) {
866 Voices[v].ADSR.sFrames--;
867 }
else if (Voices[v].ADSR.rFrames) {
868 Voices[v].ADSRVolume += Voices[v].ADSR.rVolume;
869 if (--Voices[v].ADSR.rFrames <= 0)
870 Voices[v].ADSRVolume = Voices[v].Instrument->Envelope.rVolume << 8;
873 Voices[v].NoteMaxVolume = Voices[v].NoteMaxVolume + Voices[v].VolumeSlideUp - Voices[v].VolumeSlideDown;
874 if (Voices[v].NoteMaxVolume < 0)
875 Voices[v].NoteMaxVolume = 0;
876 if (Voices[v].NoteMaxVolume > 0x40)
877 Voices[v].NoteMaxVolume = 0x40;
879 if (Voices[v].PeriodSlideOn) {
880 if (Voices[v].PeriodSlideWithLimit) {
881 int d0 = Voices[v].PeriodSlidePeriod - Voices[v].PeriodSlideLimit;
882 int d2 = Voices[v].PeriodSlideSpeed;
886 int d3 = (d0 + d2) ^ d0;
888 d0 = Voices[v].PeriodSlidePeriod + d2;
890 d0 = Voices[v].PeriodSlideLimit;
891 Voices[v].PeriodSlidePeriod = d0;
892 Voices[v].PlantPeriod = 1;
895 Voices[v].PeriodSlidePeriod += Voices[v].PeriodSlideSpeed;
896 Voices[v].PlantPeriod = 1;
900 if (Voices[v].VibratoDepth) {
901 if (Voices[v].VibratoDelay <= 0) {
902 Voices[v].VibratoPeriod = (VibratoTable[Voices[v].VibratoCurrent] * Voices[v].VibratoDepth) >> 7;
903 Voices[v].PlantPeriod = 1;
904 Voices[v].VibratoCurrent = (Voices[v].VibratoCurrent + Voices[v].VibratoSpeed) & 0x3f;
906 Voices[v].VibratoDelay--;
909 if (Voices[v].Instrument && Voices[v].PerfCurrent < Voices[v].Instrument->PList.Length) {
910 if (--Voices[v].PerfWait <= 0) {
911 int Cur = Voices[v].PerfCurrent++;
912 Voices[v].PerfWait = Voices[v].PerfSpeed;
913 if (Voices[v].PerfList->Entries[Cur].Waveform) {
914 Voices[v].Waveform = Voices[v].PerfList->Entries[Cur].Waveform - 1;
915 Voices[v].NewWaveform = 1;
916 Voices[v].PeriodPerfSlideSpeed = Voices[v].PeriodPerfSlidePeriod = 0;
919 Voices[v].PeriodPerfSlideOn = 0;
920 for (i = 0; i < 2; i++)
921 AHXPlayer_PListCommandParse(v, Voices[v].PerfList->Entries[Cur].FX[i], Voices[v].PerfList->Entries[Cur].FXParam[i]);
923 if (Voices[v].PerfList->Entries[Cur].Note) {
924 Voices[v].InstrPeriod = Voices[v].PerfList->Entries[Cur].Note;
925 Voices[v].PlantPeriod = 1;
926 Voices[v].FixedNote = Voices[v].PerfList->Entries[Cur].Fixed;
930 if (Voices[v].PerfWait)
931 Voices[v].PerfWait--;
933 Voices[v].PeriodPerfSlideSpeed = 0;
936 if (Voices[v].PeriodPerfSlideOn) {
937 Voices[v].PeriodPerfSlidePeriod -= Voices[v].PeriodPerfSlideSpeed;
938 if (Voices[v].PeriodPerfSlidePeriod)
939 Voices[v].PlantPeriod = 1;
941 if (Voices[v].Waveform == 3 - 1 && Voices[v].SquareOn) {
942 if (--Voices[v].SquareWait <= 0) {
943 int d1 = Voices[v].SquareLowerLimit;
944 int d2 = Voices[v].SquareUpperLimit;
945 int d3 = Voices[v].SquarePos;
946 if (Voices[v].SquareInit) {
947 Voices[v].SquareInit = 0;
949 Voices[v].SquareSlidingIn = 1;
950 Voices[v].SquareSign = 1;
951 }
else if (d3 >= d2) {
952 Voices[v].SquareSlidingIn = 1;
953 Voices[v].SquareSign = -1;
957 if (d1 == d3 || d2 == d3) {
958 if (Voices[v].SquareSlidingIn) {
959 Voices[v].SquareSlidingIn = 0;
961 Voices[v].SquareSign = -Voices[v].SquareSign;
964 d3 += Voices[v].SquareSign;
965 Voices[v].SquarePos = d3;
966 Voices[v].PlantSquare = 1;
967 Voices[v].SquareWait = Voices[v].Instrument->SquareSpeed;
970 if (Voices[v].FilterOn && --Voices[v].FilterWait <= 0) {
971 int d1 = Voices[v].FilterLowerLimit;
972 int d2 = Voices[v].FilterUpperLimit;
973 int d3 = Voices[v].FilterPos;
974 if (Voices[v].FilterInit) {
975 Voices[v].FilterInit = 0;
977 Voices[v].FilterSlidingIn = 1;
978 Voices[v].FilterSign = 1;
979 }
else if (d3 >= d2) {
980 Voices[v].FilterSlidingIn = 1;
981 Voices[v].FilterSign = -1;
985 int FMax = (Voices[v].FilterSpeed < 3) ? (5 - Voices[v].FilterSpeed) : 1;
986 for (i = 0; i < FMax; i++) {
987 if (d1 == d3 || d2 == d3) {
988 if (Voices[v].FilterSlidingIn) {
989 Voices[v].FilterSlidingIn = 0;
991 Voices[v].FilterSign = -Voices[v].FilterSign;
994 d3 += Voices[v].FilterSign;
996 Voices[v].FilterPos = d3;
997 Voices[v].NewWaveform = 1;
998 Voices[v].FilterWait = Voices[v].FilterSpeed - 3;
999 if (Voices[v].FilterWait < 1)
1000 Voices[v].FilterWait = 1;
1002 if (Voices[v].Waveform == 3 - 1 || Voices[v].PlantSquare) {
1006 SquarePtr = &Waves->Squares[(Voices[v].FilterPos - 0x20) * (0xfc + 0xfc + 0x80 * 0x1f + 0x80 + 0x280 * 3)];
1007 int X = Voices[v].SquarePos << (5 - Voices[v].WaveLength);
1010 Voices[v].SquareReverse = 1;
1014 SquarePtr += X << 7;
1015 int Delta = 32 >> Voices[v].WaveLength;
1016 WaveformTab[2] = Voices[v].SquareTempBuffer;
1017 for (i = 0; i < (1 << Voices[v].WaveLength) * 4; i++) {
1018 Voices[v].SquareTempBuffer[i] = *SquarePtr;
1021 Voices[v].NewWaveform = 1;
1022 Voices[v].Waveform = 3 - 1;
1023 Voices[v].PlantSquare = 0;
1025 if (Voices[v].Waveform == 4 - 1)
1026 Voices[v].NewWaveform = 1;
1028 if (Voices[v].NewWaveform) {
1029 AudioSource = WaveformTab[Voices[v].Waveform];
1030 if (Voices[v].Waveform != 3 - 1) {
1031 AudioSource += (Voices[v].FilterPos - 0x20) * (0xfc + 0xfc + 0x80 * 0x1f + 0x80 + 0x280 * 3);
1033 if (Voices[v].Waveform < 3 - 1) {
1034 AudioSource += Offsets[Voices[v].WaveLength];
1036 if (Voices[v].Waveform == 4 - 1) {
1038 AudioSource += (WNRandom & (2 * 0x280 - 1)) & ~1;
1040 WNRandom += 2239384;
1041 WNRandom = ((((WNRandom >> 8) | (WNRandom << 24)) + 782323) ^ 75) - 6735;
1043 Voices[v].AudioSource = AudioSource;
1047 Voices[v].AudioPeriod = Voices[v].InstrPeriod;
1048 if (!Voices[v].FixedNote)
1049 Voices[v].AudioPeriod += Voices[v].Transpose + Voices[v].TrackPeriod - 1;
1050 if (Voices[v].AudioPeriod > 5 * 12)
1051 Voices[v].AudioPeriod = 5 * 12;
1052 if (Voices[v].AudioPeriod < 0)
1053 Voices[v].AudioPeriod = 0;
1054 Voices[v].AudioPeriod = PeriodTable[Voices[v].AudioPeriod];
1055 if (!Voices[v].FixedNote)
1056 Voices[v].AudioPeriod += Voices[v].PeriodSlidePeriod;
1057 Voices[v].AudioPeriod += Voices[v].PeriodPerfSlidePeriod + Voices[v].VibratoPeriod;
1058 if (Voices[v].AudioPeriod > 0x0d60)
1059 Voices[v].AudioPeriod = 0x0d60;
1060 if (Voices[v].AudioPeriod < 0x0071)
1061 Voices[v].AudioPeriod = 0x0071;
1063 Voices[v].AudioVolume = ((((((((Voices[v].ADSRVolume >> 8) * Voices[v].NoteMaxVolume) >> 6) * Voices[v].PerfSubVolume) >> 6) * Voices[v].TrackMasterVolume) >> 6) * MainVolume) >> 6;
1066void AHXPlayer_SetAudio(
int v)
1068 if (!Voices[v].TrackOn) {
1069 Voices[v].VoiceVolume = 0;
1073 Voices[v].VoiceVolume = Voices[v].AudioVolume;
1074 if (Voices[v].PlantPeriod) {
1075 Voices[v].PlantPeriod = 0;
1076 Voices[v].VoicePeriod = Voices[v].AudioPeriod;
1078 if (Voices[v].NewWaveform) {
1079 if (Voices[v].Waveform == 4 - 1) {
1080 memcpy(Voices[v].VoiceBuffer, Voices[v].AudioSource, 0x280);
1084 WaveLoops = (1 << (5 - Voices[v].WaveLength)) * 5;
1085 for (i = 0; i < WaveLoops; i++)
1086 memcpy(&Voices[v].VoiceBuffer[i * 4 * (1 << Voices[v].WaveLength)], Voices[v].AudioSource, 4 * (1 << Voices[v].WaveLength));
1088 Voices[v].VoiceBuffer[0x280] = Voices[v].VoiceBuffer[0];
1092void AHXPlayer_VoiceOnOff(
int Voice,
int OnOff)
1094 if (Voice < 0 || Voice > 3)
1096 Voices[Voice].TrackOn = OnOff;
1102void AHXPlayer_PlayIRQ()
1105 if (StepWaitFrames <= 0) {
1106 if (GetNewPosition) {
1109 NextPos = (PosNr + 1 == Song.PositionNr) ? 0 : (PosNr + 1);
1110 for (i = 0; i < 4; i++) {
1111 Voices[i].Track = Positions[PosNr].Track[i];
1112 Voices[i].Transpose = Positions[PosNr].Transpose[i];
1113 Voices[i].NextTrack = Positions[NextPos].Track[i];
1114 Voices[i].NextTranspose = Positions[NextPos].Transpose[i];
1118 for (i = 0; i < 4; i++)
1119 AHXPlayer_ProcessStep(i);
1120 StepWaitFrames = Tempo;
1123 for (i = 0; i < 4; i++)
1124 AHXPlayer_ProcessFrame(i);
1126 if (Tempo > 0 && --StepWaitFrames <= 0) {
1127 if (!PatternBreak) {
1129 if (NoteNr >= Song.TrackLength) {
1130 PosJump = PosNr + 1;
1137 NoteNr = PosJumpNote;
1141 if (PosNr == Song.PositionNr) {
1143 PosNr = Song.Restart;
1149 for (a = 0; a < 4; a++)
1150 AHXPlayer_SetAudio(a);
1153void AHXPlayer_SetBoost(
int boostval)
1156 AHXOutput_SetOption(AHXOF_BOOST, Boost + 1);
1159void AHXPlayer_SetOversampling(
int enable)
1161 Oversampling = enable;
1164void AHXOutput_MixChunk(
int NrSamples,
int **mb)
1166 int v, delta, samples_to_mix, mixpos, *VolTab, i, offset, sample1, sample2, frac1, frac2, thiscount;
1169 for (v = 0; v < 4; v++) {
1170 if (Voices[v].VoiceVolume == 0)
1172 freq = Period2Freq(Voices[v].VoicePeriod);
1173 delta = (int)(freq * (1 << 16) / Frequency);
1174 samples_to_mix = NrSamples;
1176 while (samples_to_mix) {
1177 if (pos[v] > (0x280 << 16))
1178 pos[v] -= 0x280 << 16;
1179 thiscount = min(samples_to_mix, ((0x280 << 16) - pos[v] - 1) / delta + 1);
1180 samples_to_mix -= thiscount;
1181 VolTab = &VolumeTable[Voices[v].VoiceVolume][128];
1184 for (i = 0; i < thiscount; i++) {
1185 offset = pos[v] >> 16;
1186 sample1 = VolTab[(int)Voices[v].VoiceBuffer[offset]];
1187 sample2 = VolTab[(int)Voices[v].VoiceBuffer[offset + 1]];
1188 frac1 = pos[v] & ((1 << 16) - 1);
1189 frac2 = (1 << 16) - frac1;
1190 (*mb)[mixpos++] += ((sample1 * frac2) + (sample2 * frac1)) >> 16;
1194 for (i = 0; i < thiscount; i++) {
1195 (*mb)[mixpos++] += VolTab[(int)Voices[v].VoiceBuffer[pos[v] >> 16]];
1204void AHXOutput_MixBuffer(
short *target)
1206#define LOW_CLIP16 -0x8000
1207#define HI_CLIP16 0x7FFF
1208#define LOW_CLIP8 -0x80
1209#define HI_CLIP8 0x7F
1211 int NrSamples = Frequency / Hz / Song.SpeedMultiplier;
1212 int *mb = MixingBuffer;
1215 memset(MixingBuffer, 0, MixLen * Frequency / Hz *
sizeof(
int));
1216 for (f = 0; f < MixLen * Song.SpeedMultiplier ; f++) {
1217 AHXPlayer_PlayIRQ();
1218 AHXOutput_MixChunk(NrSamples, &mb);
1221 for (s = 0; s < BlockLen / (16 / 8); s++) {
1224 thissample = *(MixingBuffer + s) << 6;
1225 target[s] = thissample < LOW_CLIP16 ? LOW_CLIP16 : thissample > HI_CLIP16 ? HI_CLIP16 :