PS2SDK
PS2 Homebrew Libraries
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 
30 int 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 
36 int 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 
46 int Offsets[] = {0x00, 0x04, 0x04 + 0x08, 0x04 + 0x08 + 0x10, 0x04 + 0x08 + 0x10 + 0x20, 0x04 + 0x08 + 0x10 + 0x20 + 0x40};
47 
48 int *MixingBuffer;
49 int BlockLen;
50 int VolumeTable[65][256];
51 char VoiceBuffer[0x281]; // for oversampling optimization!
52 char *WaveformTab[4];
53 struct AHXVoice Voices[4];
54 struct AHXSong Song;
55 struct AHXWaves *Waves;
56 struct AHXPosition *Positions;
57 struct AHXStep **Tracks;
58 struct AHXInstrument *Instruments;
59 
60 short insrument_count = 0;
61 short position_count = 0;
62 short step_count = 0;
63 
64 int pos[4] = {0, 0, 0, 0}; // global to retain 'static' properties
65 
66 // Player vars
67 int StepWaitFrames, GetNewPosition, SongEndReached, TimingValue;
68 int PatternBreak;
69 int MainVolume;
70 int Playing, Tempo;
71 int PosNr, PosJump;
72 int NoteNr, PosJumpNote;
73 int WNRandom;
74 int PlayingTime;
75 
76 // Output vars
77 int Oversampling = 0;
78 int Boost = 0;
79 #define Bits 16
80 #define Frequency 48000
81 #define MixLen 2
82 #define Hz 50
83 #define BlockLen 3840
84 int Paused;
85 
86 // AHXWaves ////////////////////////////////////////////////////////////////////////////////////////////////
87 
88 void 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 
120 void 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 
132 void 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 
143 void 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 
175 void 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 
183 void 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 
202 void 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 
214 void 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 
277 int 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 
296 void 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 
324 void 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 
345 int 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
475 int 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 
489 int 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 
519 void AHXPlayer_NextPosition()
520 {
521  PosNr++;
522  if (PosNr == Song.PositionNr)
523  PosNr = 0;
524  StepWaitFrames = 0;
525  GetNewPosition = 1;
526 }
527 
528 void AHXPlayer_PrevPosition()
529 {
530  PosNr--;
531  if (PosNr < 0)
532  PosNr = 0;
533  StepWaitFrames = 0;
534  GetNewPosition = 1;
535 }
536 
537 void 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  }
690 NoNote:
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 
745 void 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 
812 void 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 
1066 void 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 
1092 void 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 
1102 void 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 
1153 void AHXPlayer_SetBoost(int boostval)
1154 {
1155  Boost = boostval;
1156  AHXOutput_SetOption(AHXOF_BOOST, Boost + 1);
1157 }
1158 
1159 void AHXPlayer_SetOversampling(int enable)
1160 {
1161  Oversampling = enable;
1162 }
1163 
1164 void 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 
1204 void 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 }
AHXPosition
Definition: ahx.h:54
AHXStep
Definition: ahx.h:59
sysclib.h
AHXPListEntry
Definition: ahx.h:19
ahx.h
AHXVoice
Definition: ahx.h:72
stdio.h
sysmem.h
AHXWaves
Definition: ahx.h:102
AHXInstrument
Definition: ahx.h:41
AHXSong
Definition: ahx.h:64