PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
AHX.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include <stdio.h>
12#include <sysclib.h>
13#include <sysmem.h>
14#include "ahx.h"
15
16// if this is defined the irx will be compiled without PRINTF output
17#define COMPACT_CODE
18
19#define malloc(size) \
20 (AllocSysMemory(0, size, NULL))
21
22#define free(ptr) \
23 (FreeSysMemory(ptr))
24
25#define Period2Freq(period) (3579545 / (period)) // accurate enough ;)
26#define min(a, b) (((a) < (b)) ? (a) : (b))
27#define AHXOF_BOOST 0
28#define AHXOI_OVERSAMPLING 1
29
30int VibratoTable[] = {
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};
35
36int PeriodTable[] = {
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};
45
46int Offsets[] = {0x00, 0x04, 0x04 + 0x08, 0x04 + 0x08 + 0x10, 0x04 + 0x08 + 0x10 + 0x20, 0x04 + 0x08 + 0x10 + 0x20 + 0x40};
47
48int *MixingBuffer;
49int BlockLen;
50int VolumeTable[65][256];
51char VoiceBuffer[0x281]; // for oversampling optimization!
52char *WaveformTab[4];
53struct AHXVoice Voices[4];
54struct AHXSong Song;
55struct AHXWaves *Waves;
56struct AHXPosition *Positions;
57struct AHXStep **Tracks;
58struct AHXInstrument *Instruments;
59
60short insrument_count = 0;
61short position_count = 0;
62short step_count = 0;
63
64int pos[4] = {0, 0, 0, 0}; // global to retain 'static' properties
65
66// Player vars
67int StepWaitFrames, GetNewPosition, SongEndReached, TimingValue;
68int PatternBreak;
69int MainVolume;
70int Playing, Tempo;
71int PosNr, PosJump;
72int NoteNr, PosJumpNote;
73int WNRandom;
74int PlayingTime;
75
76// Output vars
77int Oversampling = 0;
78int Boost = 0;
79#define Bits 16
80#define Frequency 48000
81#define MixLen 2
82#define Hz 50
83#define BlockLen 3840
84int Paused;
85
86// AHXWaves ////////////////////////////////////////////////////////////////////////////////////////////////
87
88void GenerateTriangle(char *Buffer, int Len)
89{
90 int d2 = Len;
91 int d5 = d2 >> 2;
92 int d1 = 128 / d5;
93 int d4 = -(d2 >> 1);
94 char *edi = Buffer;
95 char *esi;
96 int eax = 0;
97 int ecx;
98 for (ecx = 0; ecx < d5; ecx++) {
99 *edi++ = eax;
100 eax += d1;
101 }
102 *edi++ = 0x7f;
103 if (d5 != 1) {
104 eax = 128;
105 for (ecx = 0; ecx < d5 - 1; ecx++) {
106 eax -= d1;
107 *edi++ = eax;
108 }
109 }
110 esi = edi + d4;
111 for (ecx = 0; ecx < d5 * 2; ecx++) {
112 *edi++ = *esi++;
113 if (edi[-1] == 0x7f)
114 edi[-1] = 0x80;
115 else
116 edi[-1] = -edi[-1];
117 }
118}
119
120void GenerateSquare(char *Buffer)
121{
122 char *edi = Buffer;
123 int ebx, ecx;
124 for (ebx = 1; ebx <= 0x20; ebx++) {
125 for (ecx = 0; ecx < (0x40 - ebx) * 2; ecx++)
126 *edi++ = 0x80;
127 for (ecx = 0; ecx < ebx * 2; ecx++)
128 *edi++ = 0x7f;
129 }
130}
131
132void GenerateSawtooth(char *Buffer, int Len)
133{
134 char *edi = Buffer;
135 int ecx;
136 int ebx = 256 / (Len - 1), eax = -128;
137 for (ecx = 0; ecx < Len; ecx++) {
138 *edi++ = eax;
139 eax += ebx;
140 }
141}
142
143void GenerateWhiteNoise(char *Buffer, int Len)
144{
145 unsigned int Seed = 0x41595321;
146
147 while (Len--) {
148 if (Seed & 0x100)
149 *Buffer = (char)(Seed & 0xff);
150 else if (!(Seed & 0xffff))
151 *Buffer = 0x80;
152 else
153 *Buffer = 0x7f;
154
155 Buffer++;
156 unsigned int tmp = Seed; // ror 5
157 Seed >>= 5;
158 tmp <<= 31 - 5;
159 Seed |= tmp;
160 Seed = Seed ^ 0x9a;
161 unsigned int tmp2 = tmp = Seed; // rol 2
162 Seed <<= 2;
163 tmp >>= 31 - 2;
164 Seed |= tmp;
165 Seed += tmp2;
166 tmp = Seed ^ tmp2; // ror 5
167 Seed >>= 3;
168 tmp <<= 31 - 3;
169 Seed |= tmp;
170 }
171}
172
173// AHXVoice ////////////////////////////////////////////////////////////////////////////////////////////////
174
175void AHXVoice_Init(struct AHXVoice *pVoice)
176{
177 memset(pVoice, 0, sizeof(struct AHXVoice));
178 memset(pVoice->VoiceBuffer, 0, 0x281);
179 pVoice->TrackOn = 1;
180 pVoice->TrackMasterVolume = 0x40;
181}
182
183void AHXVoice_CalcADSR(struct AHXVoice *pVoice)
184{
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;
192}
193
194// AHXPlayer ///////////////////////////////////////////////////////////////////////////////////////////////
195
196#ifdef WIN32
197#pragma warning(disable : 4309 4305)
198#endif
199
200#define FIXEDPOINT 16 // 16 = 32-FIXEDPOINT.FIXEDPOINT
201
202void clipint(int *x)
203{
204 if (*x > (int)((u32)(127) << FIXEDPOINT)) {
205 *x = (int)((u32)(127) << FIXEDPOINT);
206 return;
207 }
208 if (*x < (int)((u32)(-128) << FIXEDPOINT)) {
209 *x = (int)((u32)(-128) << FIXEDPOINT);
210 return;
211 }
212}
213
214void GenerateFilterWaveforms(char *Buffer, char *Low, char *High)
215{
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,
219 (0x280 * 3) - 1};
220 int temp, freq, waves, i, highint, midint, lowint;
221
222 for (temp = 0, freq = 8; temp < 31; temp++, freq += 3) {
223 char *a0 = Buffer;
224 // fre = ((freq * 1.25f) / 100);
225 int v125 = (1 << FIXEDPOINT) + ((1 << FIXEDPOINT) / 4);
226 int freint = ((freq * v125) / 100); // 0x14000 ~ 1.25
227 for (waves = 0; waves < 6 + 6 + 0x20 + 1; waves++) { // 0 - 44
228 // mid = 0.f;
229 // low = 0.f;
230 midint = 0;
231 lowint = 0;
232
233 for (i = 0; i <= LengthTable[waves]; i++) {
234 // high = a0[i] - mid - low;
235 // clip(&high);
236 // mid += high * fre;
237 // clip(&mid);
238 // low += mid * fre;
239 // clip(&low);
240
241 highint = (((int)(a0[i])) << FIXEDPOINT) - midint - lowint;
242 clipint(&highint);
243 midint += (highint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
244 clipint(&midint);
245 lowint += (midint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
246 clipint(&lowint);
247 }
248 for (i = 0; i <= LengthTable[waves]; i++) {
249 // high = a0[i] - mid - low;
250 // clip(&high);
251 // mid += high * fre;
252 // clip(&mid);
253 // low += mid * fre;
254 // clip(&low);
255 // *Low++ = (char)low;
256 // *High++ = (char)high;
257
258 highint = (((int)(a0[i])) << FIXEDPOINT) - midint - lowint;
259 clipint(&highint);
260 midint += (highint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
261 clipint(&midint);
262 lowint += (midint * (freint >> (FIXEDPOINT / 2)) >> (FIXEDPOINT / 2));
263 clipint(&lowint);
264
265 char low_ = (lowint >> FIXEDPOINT);
266 char high_ = (highint >> FIXEDPOINT);
267
268 *Low++ = low_;
269 *High++ = high_;
270 }
271 a0 += LengthTable[waves] + 1;
272 // printf("start = %d, a0 = %d\n", start, a0);
273 }
274 }
275}
276
277int AHXOutput_SetOption(int Option, int Value)
278{
279
280 switch (Option) {
281 case AHXOF_BOOST: {
282 // Initialize volume table
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;
286 }
287 }
288 Boost = Value;
289 }
290 return 1;
291 default:
292 return 0;
293 }
294}
295
296void AHXPlayer_Init()
297{
298 Waves = (struct AHXWaves *)malloc(sizeof(struct AHXWaves));
299 WaveformTab[0] = Waves->Triangle04;
300 WaveformTab[1] = Waves->Sawtooth04;
301 WaveformTab[3] = Waves->WhiteNoiseBig;
302
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);
318
319 MixingBuffer = (int *)malloc(sizeof(int) * (MixLen * Frequency / Hz));
320
321 AHXOutput_SetOption(AHXOF_BOOST, Boost + 1);
322}
323
324void AHXPlayer_FreeMem()
325{
326 int i;
327 // free old mem in reverse order
328 // printf("1 Memory Allocated. %d bytes left.\n", QueryTotalFreeMemSize());
329 for (i = 1; i < Song.InstrumentNr + 1; i++) {
330 free(Instruments[i].PList.Entries);
331 free(Instruments[i].Name);
332 }
333 free(Instruments);
334
335 for (i = 0; i < Song.TrackNr + 1; i++) {
336 free(Tracks[i]);
337 }
338 free(Tracks);
339 free(Positions);
340 free(Song.Subsongs);
341 free(Song.Name);
342 // printf("2 Memory Allocated. %d bytes left.\n", QueryTotalFreeMemSize());
343}
344
345int AHXPlayer_LoadSongBuffer(void *Buffer, int Len)
346{
347 int SongLength = Len;
348 int i, j, MaxTrack;
349 unsigned char *SongBuffer = (unsigned char *)Buffer;
350 unsigned char *SBPtr = &SongBuffer[14];
351 char *NamePtr;
352
353 AHXPlayer_FreeMem();
354
355 if (SongLength < 14 || SongLength == 65536)
356 return 0;
357
358 if (SongBuffer[0] != 'T' && SongBuffer[1] != 'H' && SongBuffer[2] != 'X')
359 return 0;
360 Song.Revision = SongBuffer[3];
361 if (Song.Revision > 1)
362 return 0;
363
364 // Header ////////////////////////////////////////////
365 // Songname
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;
371
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];
378
379 // Subsongs //////////////////////////////////////////
380 Song.Subsongs = (int *)malloc(sizeof(int) * Song.SubsongNr);
381#ifndef COMPACT_CODE
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));
387#endif
388 for (i = 0; i < Song.SubsongNr; i++) {
389 if (SBPtr - SongBuffer > SongLength)
390 return 0;
391 Song.Subsongs[i] = (SBPtr[0] << 8) | SBPtr[1];
392 SBPtr += 2;
393 }
394
395 // Position List /////////////////////////////////////
396 Positions = (struct AHXPosition *)malloc(sizeof(struct AHXPosition) * Song.PositionNr);
397 for (i = 0; i < Song.PositionNr; i++) {
398 for (j = 0; j < 4; j++) {
399 if (SBPtr - SongBuffer > SongLength)
400 return 0;
401 Positions[i].Track[j] = *SBPtr++;
402 Positions[i].Transpose[j] = *(signed char *)SBPtr++;
403 }
404 }
405
406 // Tracks ////////////////////////////////////////////
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));
413 continue;
414 }
415 for (j = 0; j < Song.TrackLength; j++) {
416 if (SBPtr - SongBuffer > SongLength)
417 return 0;
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];
422 SBPtr += 3;
423 }
424 }
425
426 // Instruments ///////////////////////////////////////
427 Instruments = (struct AHXInstrument *)malloc(sizeof(struct AHXInstrument) * (Song.InstrumentNr + 1));
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)
433 return 0;
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]; // 4
440 Instruments[i].Envelope.dVolume = SBPtr[5];
441 Instruments[i].Envelope.sFrames = SBPtr[6];
442 Instruments[i].Envelope.rFrames = SBPtr[7]; // 7
443 Instruments[i].Envelope.rVolume = SBPtr[8];
444 Instruments[i].FilterLowerLimit = SBPtr[12] & 0x7f;
445 Instruments[i].VibratoDelay = SBPtr[13]; // 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; // 14
449 Instruments[i].VibratoSpeed = SBPtr[15];
450 Instruments[i].SquareLowerLimit = SBPtr[16];
451 Instruments[i].SquareUpperLimit = SBPtr[17]; // 17
452 Instruments[i].SquareSpeed = SBPtr[18];
453 Instruments[i].FilterUpperLimit = SBPtr[19] & 0x3f; // 19
454 Instruments[i].PList.Speed = SBPtr[20];
455 Instruments[i].PList.Length = SBPtr[21];
456 SBPtr += 22;
457 Instruments[i].PList.Entries = (struct AHXPListEntry *)malloc(sizeof(struct AHXPListEntry) * Instruments[i].PList.Length);
458 for (j = 0; j < Instruments[i].PList.Length; j++) {
459 if (SBPtr - SongBuffer > SongLength)
460 return 0;
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];
468 SBPtr += 4;
469 }
470 }
471 return Song.SubsongNr;
472}
473
474#ifdef WIN32
475int AHXPlayer_LoadSong(char *Filename)
476{
477 int SongLength;
478 FILE *f;
479 unsigned char SongBuffer[65536];
480 f = fopen(Filename, "rb");
481 if (!f)
482 return 0;
483 SongLength = fread(SongBuffer, 1, 65536, f);
484 fclose(f);
485 return AHXPlayer_LoadSongBuffer(SongBuffer, SongLength);
486}
487#endif
488
489int AHXPlayer_InitSubsong(int Nr)
490{
491 int v;
492
493 if (Nr > Song.SubsongNr)
494 return 0;
495
496 if (Nr == 0)
497 PosNr = 0;
498 else
499 PosNr = Song.Subsongs[Nr - 1];
500
501 PosJump = 0;
502 PatternBreak = 0;
503 MainVolume = 0x40;
504 Playing = 1;
505 NoteNr = PosJumpNote = 0;
506 Tempo = 6;
507 StepWaitFrames = 0;
508 GetNewPosition = 1;
509 SongEndReached = 0;
510 TimingValue = PlayingTime = 0;
511
512 for (v = 0; v < 4; v++) {
513 AHXVoice_Init(&Voices[v]);
514 }
515
516 return 1;
517}
518
519void AHXPlayer_NextPosition()
520{
521 PosNr++;
522 if (PosNr == Song.PositionNr)
523 PosNr = 0;
524 StepWaitFrames = 0;
525 GetNewPosition = 1;
526}
527
528void AHXPlayer_PrevPosition()
529{
530 PosNr--;
531 if (PosNr < 0)
532 PosNr = 0;
533 StepWaitFrames = 0;
534 GetNewPosition = 1;
535}
536
537void AHXPlayer_ProcessStep(int v)
538{
539 int Note, Instrument, FX, FXParam, SquareLower, SquareUpper, d3, d4, d6, Neue, Alte, i;
540
541 if (!Voices[v].TrackOn)
542 return;
543 Voices[v].VolumeSlideUp = Voices[v].VolumeSlideDown = 0;
544
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;
549
550 switch (FX) {
551 case 0x0: // Position Jump HI
552 if ((FXParam & 0xf) > 0 && (FXParam & 0xf) <= 9)
553 PosJump = FXParam & 0xf;
554 break;
555 case 0x5: // Volume Slide + Tone Portamento
556 case 0xa: // Volume Slide
557 Voices[v].VolumeSlideDown = FXParam & 0x0f;
558 Voices[v].VolumeSlideUp = FXParam >> 4;
559 break;
560 case 0xb: // Position Jump
561 PosJump = PosJump * 100 + (FXParam & 0x0f) + (FXParam >> 4) * 10;
562 PatternBreak = 1;
563 break;
564 case 0xd: // Patternbreak
565 PosJump = PosNr + 1;
566 PosJumpNote = (FXParam & 0x0f) + (FXParam >> 4) * 10;
567 if (PosJumpNote > Song.TrackLength)
568 PosJumpNote = 0;
569 PatternBreak = 1;
570 break;
571 case 0xe: // Enhanced commands
572 switch (FXParam >> 4) {
573 case 0xc: // Note Cut
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;
579 }
580 }
581 break;
582 case 0xd: // Note Delay
583 if (Voices[v].NoteDelayOn) {
584 Voices[v].NoteDelayOn = 0;
585 } else {
586 if ((FXParam & 0x0f) < Tempo) {
587 Voices[v].NoteDelayWait = FXParam & 0x0f;
588 if (Voices[v].NoteDelayWait) {
589 Voices[v].NoteDelayOn = 1;
590 return;
591 }
592 }
593 }
594 break;
595 }
596 break;
597 case 0xf: // Speed
598 Tempo = FXParam;
599 break;
600 }
601 if (Instrument) {
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]);
607 // InitOnInstrument
608 Voices[v].WaveLength = Voices[v].Instrument->WaveLength;
609 Voices[v].NoteMaxVolume = Voices[v].Instrument->Volume;
610 // InitVibrato
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;
616 // InitHardCut
617 Voices[v].HardCutRelease = Voices[v].Instrument->HardCutRelease;
618 Voices[v].HardCut = Voices[v].Instrument->HardCutReleaseFrames;
619 // InitSquare
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) {
625 int t = SquareUpper;
626 SquareUpper = SquareLower;
627 SquareLower = t;
628 }
629 Voices[v].SquareUpperLimit = SquareUpper;
630 Voices[v].SquareLowerLimit = SquareLower;
631 // InitFilter
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;
637 if (d3 & 0x80)
638 d6 |= 0x20;
639 if (d4 & 0x80)
640 d6 |= 0x40;
641 Voices[v].FilterSpeed = d6;
642 d3 &= ~0x80;
643 d4 &= ~0x80;
644 if (d3 > d4) {
645 int t = d3;
646 d3 = d4;
647 d4 = t;
648 }
649 Voices[v].FilterUpperLimit = d4;
650 Voices[v].FilterLowerLimit = d3;
651 Voices[v].FilterPos = 32;
652 // Init PerfList
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;
656 }
657 // NoInstrument
658 Voices[v].PeriodSlideOn = 0;
659
660 switch (FX) {
661 case 0x4: // Override filter
662 break;
663 case 0x9: // Set Squarewave-Offset
664 Voices[v].SquarePos = FXParam >> (5 - Voices[v].WaveLength);
665 Voices[v].PlantSquare = 1;
666 Voices[v].IgnoreSquare = 1;
667 break;
668 case 0x5: // Tone Portamento + Volume Slide
669 case 0x3: // Tone Portamento (Period Slide Up/Down w/ Limit)
670 if (FXParam != 0)
671 Voices[v].PeriodSlideSpeed = FXParam;
672 if (Note) {
673 Neue = PeriodTable[Note];
674 Alte = PeriodTable[Voices[v].TrackPeriod];
675 Alte -= Neue;
676 Neue = Alte + Voices[v].PeriodSlidePeriod;
677 if (Neue)
678 Voices[v].PeriodSlideLimit = -Alte;
679 }
680 Voices[v].PeriodSlideOn = 1;
681 Voices[v].PeriodSlideWithLimit = 1;
682 goto NoNote;
683 }
684
685 // Note anschlagen
686 if (Note) {
687 Voices[v].TrackPeriod = Note;
688 Voices[v].PlantPeriod = 1;
689 }
690NoNote:
691 switch (FX) {
692 case 0x1: // Portamento up (Period slide down)
693 Voices[v].PeriodSlideSpeed = -FXParam;
694 Voices[v].PeriodSlideOn = 1;
695 Voices[v].PeriodSlideWithLimit = 0;
696 break;
697 case 0x2: // Portamento down (Period slide up)
698 Voices[v].PeriodSlideSpeed = FXParam;
699 Voices[v].PeriodSlideOn = 1;
700 Voices[v].PeriodSlideWithLimit = 0;
701 break;
702 case 0xc: // Volume
703 if (FXParam <= 0x40)
704 Voices[v].NoteMaxVolume = FXParam;
705 else {
706 FXParam -= 0x50;
707 if (FXParam <= 0x40)
708 for (i = 0; i < 4; i++)
709 Voices[i].TrackMasterVolume = FXParam;
710 else {
711 FXParam -= 0xa0 - 0x50;
712 if (FXParam <= 0x40)
713 Voices[v].TrackMasterVolume = FXParam;
714 }
715 }
716 break;
717 case 0xe: // Enhanced commands
718 switch (FXParam >> 4) {
719 case 0x1: // Fineslide up (Period fineslide down)
720 Voices[v].PeriodSlidePeriod = -(FXParam & 0x0f);
721 Voices[v].PlantPeriod = 1;
722 break;
723 case 0x2: // Fineslide down (Period fineslide up)
724 Voices[v].PeriodSlidePeriod = FXParam & 0x0f;
725 Voices[v].PlantPeriod = 1;
726 break;
727 case 0x4: // Vibrato control
728 Voices[v].VibratoDepth = FXParam & 0x0f;
729 break;
730 case 0xa: // Finevolume up
731 Voices[v].NoteMaxVolume += FXParam & 0x0f;
732 if (Voices[v].NoteMaxVolume > 0x40)
733 Voices[v].NoteMaxVolume = 0x40;
734 break;
735 case 0xb: // Finevolume down
736 Voices[v].NoteMaxVolume -= FXParam & 0x0f;
737 if (Voices[v].NoteMaxVolume < 0)
738 Voices[v].NoteMaxVolume = 0;
739 break;
740 }
741 break;
742 }
743}
744
745void AHXPlayer_PListCommandParse(int v, int FX, int FXParam)
746{
747 switch (FX) {
748 case 0:
749 if (Song.Revision > 0 && FXParam != 0) {
750 if (Voices[v].IgnoreFilter) {
751 Voices[v].FilterPos = Voices[v].IgnoreFilter;
752 Voices[v].IgnoreFilter = 0;
753 } else
754 Voices[v].FilterPos = FXParam;
755 Voices[v].NewWaveform = 1;
756 }
757 break;
758 case 1:
759 Voices[v].PeriodPerfSlideSpeed = FXParam;
760 Voices[v].PeriodPerfSlideOn = 1;
761 break;
762 case 2:
763 Voices[v].PeriodPerfSlideSpeed = -FXParam;
764 Voices[v].PeriodPerfSlideOn = 1;
765 break;
766 case 3: // Init Square Modulation
767 if (!Voices[v].IgnoreSquare) {
768 Voices[v].SquarePos = FXParam >> (5 - Voices[v].WaveLength);
769 } else
770 Voices[v].IgnoreSquare = 0;
771 break;
772 case 4: // Start/Stop Modulation
773 if (Song.Revision == 0 || FXParam == 0) {
774 Voices[v].SquareInit = (Voices[v].SquareOn ^= 1);
775 Voices[v].SquareSign = 1;
776 } else {
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;
782 }
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;
788 }
789 }
790 break;
791 case 5: // Jump to Step [xx]
792 Voices[v].PerfCurrent = FXParam;
793 break;
794 case 6: // Set Volume
795 if (FXParam > 0x40) {
796 if ((FXParam -= 0x50) >= 0) {
797 if (FXParam <= 0x40)
798 Voices[v].PerfSubVolume = FXParam;
799 else if ((FXParam -= 0xa0 - 0x50) >= 0)
800 if (FXParam <= 0x40)
801 Voices[v].TrackMasterVolume = FXParam;
802 }
803 } else
804 Voices[v].NoteMaxVolume = FXParam;
805 break;
806 case 7: // set speed
807 Voices[v].PerfSpeed = Voices[v].PerfWait = FXParam;
808 break;
809 }
810}
811
812void AHXPlayer_ProcessFrame(int v)
813{
814 int i;
815 char *AudioSource;
816
817 if (!Voices[v].TrackOn)
818 return;
819
820 if (Voices[v].NoteDelayOn) {
821 if (Voices[v].NoteDelayWait <= 0)
822 AHXPlayer_ProcessStep(v);
823 else
824 Voices[v].NoteDelayWait--;
825 }
826 if (Voices[v].HardCut) {
827 int NextInstrument;
828 if (NoteNr + 1 < Song.TrackLength)
829 NextInstrument = Tracks[Voices[v].Track][NoteNr + 1].Instrument;
830 else
831 NextInstrument = Tracks[Voices[v].NextTrack][0].Instrument;
832 if (NextInstrument) {
833 int d1 = Tempo - Voices[v].HardCut;
834 if (d1 < 0)
835 d1 = 0;
836 if (!Voices[v].NoteCutOn) {
837 Voices[v].NoteCutOn = 1;
838 Voices[v].NoteCutWait = d1;
839 Voices[v].HardCutReleaseF = -(d1 - Tempo);
840 } else
841 Voices[v].HardCut = 0;
842 }
843 }
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;
851 } else
852 Voices[v].NoteMaxVolume = 0;
853 } else
854 Voices[v].NoteCutWait--;
855 }
856 // adsrEnvelope
857 if (Voices[v].ADSR.aFrames) {
858 Voices[v].ADSRVolume += Voices[v].ADSR.aVolume; // Delta
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; // Delta
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; // Delta
869 if (--Voices[v].ADSR.rFrames <= 0)
870 Voices[v].ADSRVolume = Voices[v].Instrument->Envelope.rVolume << 8;
871 }
872 // VolumeSlide
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;
878 // Portamento
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;
883 if (d0 > 0)
884 d2 = -d2;
885 if (d0) {
886 int d3 = (d0 + d2) ^ d0;
887 if (d3 >= 0)
888 d0 = Voices[v].PeriodSlidePeriod + d2;
889 else
890 d0 = Voices[v].PeriodSlideLimit;
891 Voices[v].PeriodSlidePeriod = d0;
892 Voices[v].PlantPeriod = 1;
893 }
894 } else {
895 Voices[v].PeriodSlidePeriod += Voices[v].PeriodSlideSpeed;
896 Voices[v].PlantPeriod = 1;
897 }
898 }
899 // Vibrato
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;
905 } else
906 Voices[v].VibratoDelay--;
907 }
908 // PList
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;
917 }
918 // Holdwave
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]);
922 // GetNote
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;
927 }
928 }
929 } else {
930 if (Voices[v].PerfWait)
931 Voices[v].PerfWait--;
932 else
933 Voices[v].PeriodPerfSlideSpeed = 0;
934 }
935 // PerfPortamento
936 if (Voices[v].PeriodPerfSlideOn) {
937 Voices[v].PeriodPerfSlidePeriod -= Voices[v].PeriodPerfSlideSpeed;
938 if (Voices[v].PeriodPerfSlidePeriod)
939 Voices[v].PlantPeriod = 1;
940 }
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;
948 if (d3 <= d1) {
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;
954 }
955 }
956 // NoSquareInit
957 if (d1 == d3 || d2 == d3) {
958 if (Voices[v].SquareSlidingIn) {
959 Voices[v].SquareSlidingIn = 0;
960 } else {
961 Voices[v].SquareSign = -Voices[v].SquareSign;
962 }
963 }
964 d3 += Voices[v].SquareSign;
965 Voices[v].SquarePos = d3;
966 Voices[v].PlantSquare = 1;
967 Voices[v].SquareWait = Voices[v].Instrument->SquareSpeed;
968 }
969 }
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;
976 if (d3 <= d1) {
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;
982 }
983 }
984 // NoFilterInit
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;
990 } else {
991 Voices[v].FilterSign = -Voices[v].FilterSign;
992 }
993 }
994 d3 += Voices[v].FilterSign;
995 }
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;
1001 }
1002 if (Voices[v].Waveform == 3 - 1 || Voices[v].PlantSquare) {
1003 char *SquarePtr;
1004
1005 // CalcSquare
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);
1008 if (X > 0x20) {
1009 X = 0x40 - X;
1010 Voices[v].SquareReverse = 1;
1011 }
1012 // OkDownSquare
1013 if (--X)
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;
1019 SquarePtr += Delta;
1020 }
1021 Voices[v].NewWaveform = 1;
1022 Voices[v].Waveform = 3 - 1;
1023 Voices[v].PlantSquare = 0;
1024 }
1025 if (Voices[v].Waveform == 4 - 1)
1026 Voices[v].NewWaveform = 1;
1027
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);
1032 }
1033 if (Voices[v].Waveform < 3 - 1) {
1034 AudioSource += Offsets[Voices[v].WaveLength];
1035 }
1036 if (Voices[v].Waveform == 4 - 1) {
1037 // AddRandomMoving
1038 AudioSource += (WNRandom & (2 * 0x280 - 1)) & ~1;
1039 // GoOnRandom
1040 WNRandom += 2239384;
1041 WNRandom = ((((WNRandom >> 8) | (WNRandom << 24)) + 782323) ^ 75) - 6735;
1042 }
1043 Voices[v].AudioSource = AudioSource;
1044 }
1045 // StillHoldWaveform
1046 // AudioInitPeriod
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;
1062 // AudioInitVolume
1063 Voices[v].AudioVolume = ((((((((Voices[v].ADSRVolume >> 8) * Voices[v].NoteMaxVolume) >> 6) * Voices[v].PerfSubVolume) >> 6) * Voices[v].TrackMasterVolume) >> 6) * MainVolume) >> 6;
1064}
1065
1066void AHXPlayer_SetAudio(int v)
1067{
1068 if (!Voices[v].TrackOn) {
1069 Voices[v].VoiceVolume = 0;
1070 return;
1071 }
1072
1073 Voices[v].VoiceVolume = Voices[v].AudioVolume;
1074 if (Voices[v].PlantPeriod) {
1075 Voices[v].PlantPeriod = 0;
1076 Voices[v].VoicePeriod = Voices[v].AudioPeriod;
1077 }
1078 if (Voices[v].NewWaveform) {
1079 if (Voices[v].Waveform == 4 - 1) {
1080 memcpy(Voices[v].VoiceBuffer, Voices[v].AudioSource, 0x280);
1081 } else {
1082 int i, WaveLoops;
1083
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));
1087 }
1088 Voices[v].VoiceBuffer[0x280] = Voices[v].VoiceBuffer[0];
1089 }
1090}
1091
1092void AHXPlayer_VoiceOnOff(int Voice, int OnOff)
1093{
1094 if (Voice < 0 || Voice > 3)
1095 return;
1096 Voices[Voice].TrackOn = OnOff;
1097}
1098
1099// AHXOutput ///////////////////////////////////////////////////////////////////////////////////////////////
1100
1101
1102void AHXPlayer_PlayIRQ()
1103{
1104 int i, a;
1105 if (StepWaitFrames <= 0) {
1106 if (GetNewPosition) {
1107 int NextPos;
1108
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];
1115 }
1116 GetNewPosition = 0;
1117 }
1118 for (i = 0; i < 4; i++)
1119 AHXPlayer_ProcessStep(i);
1120 StepWaitFrames = Tempo;
1121 }
1122 // DoFrameStuff
1123 for (i = 0; i < 4; i++)
1124 AHXPlayer_ProcessFrame(i);
1125 PlayingTime++;
1126 if (Tempo > 0 && --StepWaitFrames <= 0) {
1127 if (!PatternBreak) {
1128 NoteNr++;
1129 if (NoteNr >= Song.TrackLength) {
1130 PosJump = PosNr + 1;
1131 PosJumpNote = 0;
1132 PatternBreak = 1;
1133 }
1134 }
1135 if (PatternBreak) {
1136 PatternBreak = 0;
1137 NoteNr = PosJumpNote;
1138 PosJumpNote = 0;
1139 PosNr = PosJump;
1140 PosJump = 0;
1141 if (PosNr == Song.PositionNr) {
1142 SongEndReached = 1;
1143 PosNr = Song.Restart;
1144 }
1145 GetNewPosition = 1;
1146 }
1147 }
1148 // RemainPosition
1149 for (a = 0; a < 4; a++)
1150 AHXPlayer_SetAudio(a);
1151}
1152
1153void AHXPlayer_SetBoost(int boostval)
1154{
1155 Boost = boostval;
1156 AHXOutput_SetOption(AHXOF_BOOST, Boost + 1);
1157}
1158
1159void AHXPlayer_SetOversampling(int enable)
1160{
1161 Oversampling = enable;
1162}
1163
1164void AHXOutput_MixChunk(int NrSamples, int **mb)
1165{
1166 int v, delta, samples_to_mix, mixpos, *VolTab, i, offset, sample1, sample2, frac1, frac2, thiscount;
1167 long freq;
1168
1169 for (v = 0; v < 4; v++) {
1170 if (Voices[v].VoiceVolume == 0)
1171 continue;
1172 freq = Period2Freq(Voices[v].VoicePeriod);
1173 delta = (int)(freq * (1 << 16) / Frequency);
1174 samples_to_mix = NrSamples;
1175 mixpos = 0;
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];
1182 // INNER LOOP
1183 if (Oversampling) {
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;
1191 pos[v] += delta;
1192 }
1193 } else {
1194 for (i = 0; i < thiscount; i++) {
1195 (*mb)[mixpos++] += VolTab[(int)Voices[v].VoiceBuffer[pos[v] >> 16]];
1196 pos[v] += delta;
1197 }
1198 }
1199 } // while
1200 } // v = 0-3
1201 *mb += NrSamples;
1202}
1203
1204void AHXOutput_MixBuffer(short *target)
1205{
1206#define LOW_CLIP16 -0x8000
1207#define HI_CLIP16 0x7FFF
1208#define LOW_CLIP8 -0x80
1209#define HI_CLIP8 0x7F
1210 int f;
1211 int NrSamples = Frequency / Hz / Song.SpeedMultiplier;
1212 int *mb = MixingBuffer;
1213 int s;
1214
1215 memset(MixingBuffer, 0, MixLen * Frequency / Hz * sizeof(int));
1216 for (f = 0; f < MixLen * Song.SpeedMultiplier /* MixLen = # frames */; f++) {
1217 AHXPlayer_PlayIRQ();
1218 AHXOutput_MixChunk(NrSamples, &mb);
1219 } // frames
1220
1221 for (s = 0; s < BlockLen / (16 / 8); s++) {
1222 int thissample;
1223
1224 thissample = *(MixingBuffer + s) << 6; // 16 bit
1225 target[s] = thissample < LOW_CLIP16 ? LOW_CLIP16 : thissample > HI_CLIP16 ? HI_CLIP16 :
1226 thissample;
1227 }
1228}
Definition ahx.h:20
Definition ahx.h:65
Definition ahx.h:60
Definition ahx.h:73