summaryrefslogtreecommitdiffstats
path: root/apps/plugins/mikmod/mikmod_internals.h
blob: e6ba1875c0086a968a45fa42547dfab078f02deb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
/*	MikMod sound library
	(c) 1998, 1999, 2005 Miodrag Vallat and others - see file AUTHORS for
	complete list.

	This library is free software; you can redistribute it and/or modify
	it under the terms of the GNU Library General Public License as
	published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License for more details.

	You should have received a copy of the GNU Library General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA.
*/

/*==============================================================================

  MikMod sound library internal definitions

  ==============================================================================*/

#ifndef _MIKMOD_INTERNALS_H
#define _MIKMOD_INTERNALS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdarg.h>

#if defined(_MSC_VER) && !defined(__cplusplus) && !defined(HAVE_CONFIG_H)
#define inline __inline
#endif

#include "mikmod.h"

#ifndef MIKMOD_UNIX
#if (defined(unix) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) && \
   !(defined(_MIKMOD_WIN32) || defined(_MIKMOD_OS2) || defined(_MIKMOD_DOS) || defined(_MIKMOD_AMIGA) || defined(macintosh))
#define MIKMOD_UNIX 1
#else
#define MIKMOD_UNIX 0
#endif
#endif /* MIKMOD_UNIX */

/*========== More type definitions */

/* SLONGLONG: 64bit, signed */
#if !defined(_WIN32) && \
   (defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x64_64) || defined(__powerpc64__))
typedef long            SLONGLONG;
#define NATIVE_64BIT_INT
#elif defined(_WIN64) /* win64 is LLP64, not LP64  */
#define NATIVE_64BIT_INT
typedef long long       SLONGLONG;
#elif defined(__WATCOMC__)
typedef __int64         SLONGLONG;
#elif defined(_WIN32) && !defined(__MWERKS__)
typedef LONGLONG        SLONGLONG;
#elif defined(macintosh) && !TYPE_LONGLONG
#include <Types.h>
typedef SInt64          SLONGLONG;
#else
typedef long long       SLONGLONG;
#endif
typedef int __s64_typetest [(sizeof(SLONGLONG)==8) * 2 - 1];

/* pointer-sized signed int (ssize_t/intptr_t) : */
#if defined(_WIN64) /* win64 is LLP64, not LP64  */
typedef long long       SINTPTR_T;
#else
/* long should be pointer-sized for all others : */
typedef long            SINTPTR_T;
#endif
typedef int __iptr_typetest [(sizeof(SINTPTR_T)==sizeof(void*)) * 2 - 1];

/*========== Error handling */

#define _mm_errno MikMod_errno
#define _mm_critical MikMod_critical
extern MikMod_handler_t _mm_errorhandler;

/*========== MT stuff */

#ifdef HAVE_PTHREAD
#include <pthread.h>
#define DECLARE_MUTEX(name) \
        extern pthread_mutex_t _mm_mutex_##name
#define MUTEX_LOCK(name)    \
        pthread_mutex_lock(&_mm_mutex_##name)
#define MUTEX_UNLOCK(name)  \
        pthread_mutex_unlock(&_mm_mutex_##name)

#elif defined(__OS2__)||defined(__EMX__)
#define DECLARE_MUTEX(name) \
        extern HMTX _mm_mutex_##name
#define MUTEX_LOCK(name)    \
        if(_mm_mutex_##name)\
            DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT)
#define MUTEX_UNLOCK(name)  \
        if(_mm_mutex_##name)\
            DosReleaseMutexSem(_mm_mutex_##name)

#elif defined(_WIN32)
#include <windows.h>
#define DECLARE_MUTEX(name) \
        extern HANDLE _mm_mutex_##name
#define MUTEX_LOCK(name)    \
        if(_mm_mutex_##name)\
            WaitForSingleObject(_mm_mutex_##name,INFINITE)
#define MUTEX_UNLOCK(name)  \
        if(_mm_mutex_##name)\
            ReleaseMutex(_mm_mutex_##name)

#else
#define DECLARE_MUTEX(name) \
        extern void *_mm_mutex_##name
#define MUTEX_LOCK(name)
#define MUTEX_UNLOCK(name)
#endif

DECLARE_MUTEX(lists);
DECLARE_MUTEX(vars);

/*========== Replacement funcs */

//extern int strcasecmp (const char *__s1, const char *__s2);

/*========== Portable file I/O */

extern MREADER* _mm_new_mem_reader(const void *buffer, long len);
extern void _mm_delete_mem_reader(MREADER *reader);

extern MREADER* _mm_new_file_reader(int fp);
extern void _mm_delete_file_reader(MREADER*);

extern MWRITER* _mm_new_file_writer(int fp);
extern void _mm_delete_file_writer(MWRITER*);

extern int _mm_FileExists(const CHAR *fname);

#define _mm_write_SBYTE(x,y)    y->Put(y,(int)x)
#define _mm_write_UBYTE(x,y)    y->Put(y,(int)x)

#define _mm_read_SBYTE(x)       (SBYTE)x->Get(x)
#define _mm_read_UBYTE(x)       (UBYTE)x->Get(x)
#define _mm_skip_BYTE(x)        (void)x->Get(x)

#define _mm_write_SBYTES(x,y,z) z->Write(z,(const void *)x,y)
#define _mm_write_UBYTES(x,y,z) z->Write(z,(const void *)x,y)
#define _mm_read_SBYTES(x,y,z)  z->Read(z,(void *)x,y)
#define _mm_read_UBYTES(x,y,z)  z->Read(z,(void *)x,y)

#define _mm_fseek(x,y,z)        x->Seek(x,y,z)
#define _mm_ftell(x)            x->Tell(x)
#define _mm_rewind(x)           _mm_fseek(x,0,SEEK_SET)

#define _mm_eof(x)              x->Eof(x)

extern void _mm_iobase_setcur(MREADER*);
extern void _mm_iobase_revert(MREADER*);
extern int _mm_fopen(const CHAR *, const CHAR *);
extern int  _mm_fclose(int);
extern void _mm_write_string(const CHAR*,MWRITER*);
extern int _mm_read_string (CHAR*,int,MREADER*);

extern SWORD _mm_read_M_SWORD(MREADER*);
extern SWORD _mm_read_I_SWORD(MREADER*);
extern UWORD _mm_read_M_UWORD(MREADER*);
extern UWORD _mm_read_I_UWORD(MREADER*);

extern SLONG _mm_read_M_SLONG(MREADER*);
extern SLONG _mm_read_I_SLONG(MREADER*);
extern ULONG _mm_read_M_ULONG(MREADER*);
extern ULONG _mm_read_I_ULONG(MREADER*);

extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);
extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);

extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);
extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);

extern void _mm_write_M_SWORD(SWORD,MWRITER*);
extern void _mm_write_I_SWORD(SWORD,MWRITER*);
extern void _mm_write_M_UWORD(UWORD,MWRITER*);
extern void _mm_write_I_UWORD(UWORD,MWRITER*);

extern void _mm_write_M_SLONG(SLONG,MWRITER*);
extern void _mm_write_I_SLONG(SLONG,MWRITER*);
extern void _mm_write_M_ULONG(ULONG,MWRITER*);
extern void _mm_write_I_ULONG(ULONG,MWRITER*);

extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);
extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);

extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);
extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*);

/*========== Samples */

#define MAX_SAMPLE_SIZE 0x10000000 /* a sane value guaranteed to not overflow an SLONG */

/* This is a handle of sorts attached to any sample registered with
   SL_RegisterSample.  Generally, this only need be used or changed by the
   loaders and drivers of mikmod. */
typedef struct SAMPLOAD {
    struct SAMPLOAD *next;

    ULONG    length;       /* length of sample (in samples!) */
    ULONG    loopstart;    /* repeat position (relative to start, in samples) */
    ULONG    loopend;      /* repeat end */
    UWORD    infmt,outfmt;
    int      scalefactor;
    SAMPLE*  sample;
    MREADER* reader;
} SAMPLOAD;

/*========== Sample and waves loading interface */

extern void      SL_HalveSample(SAMPLOAD*,int);
extern void      SL_Sample8to16(SAMPLOAD*);
extern void      SL_Sample16to8(SAMPLOAD*);
extern void      SL_SampleSigned(SAMPLOAD*);
extern void      SL_SampleUnsigned(SAMPLOAD*);
extern int       SL_LoadSamples(void);
extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
extern int       SL_Load(void*,SAMPLOAD*,ULONG);
extern int      SL_Init(SAMPLOAD*);
extern void      SL_Exit(SAMPLOAD*);

/*========== Internal module representation (UniMod) interface */

/* number of notes in an octave */
#define OCTAVE 12

extern void   UniSetRow(UBYTE*);
extern UBYTE  UniGetByte(void);
extern UWORD  UniGetWord(void);
extern UBYTE* UniFindRow(UBYTE*,UWORD);
extern void   UniSkipOpcode(void);
extern void   UniReset(void);
extern void   UniWriteByte(UBYTE);
extern void   UniWriteWord(UWORD);
extern void   UniNewline(void);
extern UBYTE* UniDup(void);
extern int   UniInit(void);
extern void   UniCleanup(void);
extern void   UniEffect(UWORD,UWORD);
#define UniInstrument(x)   UniEffect(UNI_INSTRUMENT,x)
#define UniNote(x)         UniEffect(UNI_NOTE,x)
extern void   UniPTEffect(UBYTE,UBYTE);
extern void   UniVolEffect(UWORD,UBYTE);

/*========== Module Commands */

enum {
 /* Simple note */
    UNI_NOTE = 1,
 /* Instrument change */
    UNI_INSTRUMENT,
 /* Protracker effects */
    UNI_PTEFFECT0,  /* arpeggio */
    UNI_PTEFFECT1,  /* porta up */
    UNI_PTEFFECT2,  /* porta down */
    UNI_PTEFFECT3,  /* porta to note */
    UNI_PTEFFECT4,  /* vibrato */
    UNI_PTEFFECT5,  /* dual effect 3+A */
    UNI_PTEFFECT6,  /* dual effect 4+A */
    UNI_PTEFFECT7,  /* tremolo */
    UNI_PTEFFECT8,  /* pan */
    UNI_PTEFFECT9,  /* sample offset */
    UNI_PTEFFECTA,  /* volume slide */
    UNI_PTEFFECTB,  /* pattern jump */
    UNI_PTEFFECTC,  /* set volume */
    UNI_PTEFFECTD,  /* pattern break */
    UNI_PTEFFECTE,  /* extended effects */
    UNI_PTEFFECTF,  /* set speed */
 /* Scream Tracker effects */
    UNI_S3MEFFECTA, /* set speed */
    UNI_S3MEFFECTD, /* volume slide */
    UNI_S3MEFFECTE, /* porta down */
    UNI_S3MEFFECTF, /* porta up */
    UNI_S3MEFFECTI, /* tremor */
    UNI_S3MEFFECTQ, /* retrig */
    UNI_S3MEFFECTR, /* tremolo */
    UNI_S3MEFFECTT, /* set tempo */
    UNI_S3MEFFECTU, /* fine vibrato */
    UNI_KEYOFF,     /* note off */
 /* Fast Tracker effects */
    UNI_KEYFADE,    /* note fade */
    UNI_VOLEFFECTS, /* volume column effects */
    UNI_XMEFFECT4,  /* vibrato */
    UNI_XMEFFECT6,  /* dual effect 4+A */
    UNI_XMEFFECTA,  /* volume slide */
    UNI_XMEFFECTE1, /* fine porta up */
    UNI_XMEFFECTE2, /* fine porta down */
    UNI_XMEFFECTEA, /* fine volume slide up */
    UNI_XMEFFECTEB, /* fine volume slide down */
    UNI_XMEFFECTG,  /* set global volume */
    UNI_XMEFFECTH,  /* global volume slide */
    UNI_XMEFFECTL,  /* set envelope position */
    UNI_XMEFFECTP,  /* pan slide */
    UNI_XMEFFECTX1, /* extra fine porta up */
    UNI_XMEFFECTX2, /* extra fine porta down */
 /* Impulse Tracker effects */
    UNI_ITEFFECTG,  /* porta to note */
    UNI_ITEFFECTH,  /* vibrato */
    UNI_ITEFFECTI,  /* tremor (xy not incremented) */
    UNI_ITEFFECTM,  /* set channel volume */
    UNI_ITEFFECTN,  /* slide / fineslide channel volume */
    UNI_ITEFFECTP,  /* slide / fineslide channel panning */
    UNI_ITEFFECTT,  /* slide tempo */
    UNI_ITEFFECTU,  /* fine vibrato */
    UNI_ITEFFECTW,  /* slide / fineslide global volume */
    UNI_ITEFFECTY,  /* panbrello */
    UNI_ITEFFECTZ,  /* resonant filters */
    UNI_ITEFFECTS0,
 /* UltraTracker effects */
    UNI_ULTEFFECT9, /* Sample fine offset */
 /* OctaMED effects */
    UNI_MEDSPEED,
    UNI_MEDEFFECTF1,/* play note twice */
    UNI_MEDEFFECTF2,/* delay note */
    UNI_MEDEFFECTF3,/* play note three times */
 /* Oktalyzer effects */
    UNI_OKTARP,     /* arpeggio */

    UNI_LAST
};

extern const UWORD unioperands[UNI_LAST];

/* IT / S3M Extended SS effects: */
enum {
    SS_GLISSANDO = 1,
    SS_FINETUNE,
    SS_VIBWAVE,
    SS_TREMWAVE,
    SS_PANWAVE,
    SS_FRAMEDELAY,
    SS_S7EFFECTS,
    SS_PANNING,
    SS_SURROUND,
    SS_HIOFFSET,
    SS_PATLOOP,
    SS_NOTECUT,
    SS_NOTEDELAY,
    SS_PATDELAY
};

/* IT Volume column effects */
enum {
    VOL_VOLUME = 1,
    VOL_PANNING,
    VOL_VOLSLIDE,
    VOL_PITCHSLIDEDN,
    VOL_PITCHSLIDEUP,
    VOL_PORTAMENTO,
    VOL_VIBRATO
};

/* IT resonant filter information */

#define UF_MAXMACRO     0x10
#define UF_MAXFILTER    0x100

#define FILT_CUT        0x80
#define FILT_RESONANT   0x81

typedef struct FILTER {
    UBYTE filter,inf;
} FILTER;

/*========== Instruments */

/* Instrument format flags */
#define IF_OWNPAN       1
#define IF_PITCHPAN     2

/* Envelope flags: */
#define EF_ON           1
#define EF_SUSTAIN      2
#define EF_LOOP         4
#define EF_VOLENV       8

/* New Note Action Flags */
#define NNA_CUT         0
#define NNA_CONTINUE    1
#define NNA_OFF         2
#define NNA_FADE        3

#define NNA_MASK        3

#define DCT_OFF         0
#define DCT_NOTE        1
#define DCT_SAMPLE      2
#define DCT_INST        3

#define DCA_CUT         0
#define DCA_OFF         1
#define DCA_FADE        2

#define KEY_KICK        0
#define KEY_OFF         1
#define KEY_FADE        2
#define KEY_KILL        (KEY_OFF|KEY_FADE)

#define KICK_ABSENT     0
#define KICK_NOTE       1
#define KICK_KEYOFF     2
#define KICK_ENV        4

#define AV_IT           1   /* IT vs. XM vibrato info */

/*========== Playing */

#define POS_NONE        (-2)    /* no loop position defined */

#define LAST_PATTERN    (UWORD)(-1) /* special ``end of song'' pattern */

typedef struct ENVPR {
    UBYTE  flg;     /* envelope flag */
    UBYTE  pts;     /* number of envelope points */
    UBYTE  susbeg;  /* envelope sustain index begin */
    UBYTE  susend;  /* envelope sustain index end */
    UBYTE  beg;     /* envelope loop begin */
    UBYTE  end;     /* envelope loop end */
    SWORD  p;       /* current envelope counter */
    UWORD  a;       /* envelope index a */
    UWORD  b;       /* envelope index b */
    ENVPT* env;     /* envelope points */
} ENVPR;

typedef struct MP_CHANNEL {
    INSTRUMENT* i;
    SAMPLE *s;
    UBYTE  sample;      /* which sample number */
    UBYTE  note;        /* the audible note as heard, direct rep of period */
    SWORD  outvolume;   /* output volume (vol + sampcol + instvol) */
    SBYTE  chanvol;     /* channel's "global" volume */
    UWORD  fadevol;     /* fading volume rate */
    SWORD  panning;     /* panning position */
    UBYTE  kick;        /* if true = sample has to be restarted */
    UBYTE  kick_flag;   /* kick has been true */
    UWORD  period;      /* period to play the sample at */
    UBYTE  nna;         /* New note action type + master/slave flags */

    UBYTE  volflg;      /* volume envelope settings */
    UBYTE  panflg;      /* panning envelope settings */
    UBYTE  pitflg;      /* pitch envelope settings */

    UBYTE  keyoff;      /* if true = fade out and stuff */
    SWORD  handle;      /* which sample-handle */
    UBYTE  notedelay;   /* (used for note delay) */
    SLONG  start;       /* The starting byte index in the sample */
} MP_CHANNEL;

typedef struct MP_CONTROL {
    struct MP_CHANNEL   main;

    struct MP_VOICE*    slave;  /* Audio Slave of current effects control channel */

    UBYTE   slavechn;   /* Audio Slave of current effects control channel */
    UBYTE   muted;      /* if set, channel not played */
    UWORD   ultoffset;  /* fine sample offset memory */
    UBYTE   anote;      /* the note that indexes the audible */
    UBYTE   oldnote;
    SWORD   ownper;
    SWORD   ownvol;
    UBYTE   dca;        /* duplicate check action */
    UBYTE   dct;        /* duplicate check type */
    UBYTE*  row;        /* row currently playing on this channel */
    SBYTE   retrig;     /* retrig value (0 means don't retrig) */
    ULONG   speed;      /* what finetune to use */
    SWORD   volume;     /* amiga volume (0 t/m 64) to play the sample at */

    SWORD   tmpvolume;  /* tmp volume */
    UWORD   tmpperiod;  /* tmp period */
    UWORD   wantedperiod;/* period to slide to (with effect 3 or 5) */

    UBYTE   arpmem;     /* arpeggio command memory */
    UBYTE   pansspd;    /* panslide speed */
    UWORD   slidespeed;
    UWORD   portspeed;  /* noteslide speed (toneportamento) */

    UBYTE   s3mtremor;  /* s3m tremor (effect I) counter */
    UBYTE   s3mtronof;  /* s3m tremor ontime/offtime */
    UBYTE   s3mvolslide;/* last used volslide */
    SBYTE   sliding;
    UBYTE   s3mrtgspeed;/* last used retrig speed */
    UBYTE   s3mrtgslide;/* last used retrig slide */

    UBYTE   glissando;  /* glissando (0 means off) */
    UBYTE   wavecontrol;

    SBYTE   vibpos;     /* current vibrato position */
    UBYTE   vibspd;     /* "" speed */
    UBYTE   vibdepth;   /* "" depth */

    SBYTE   trmpos;     /* current tremolo position */
    UBYTE   trmspd;     /* "" speed */
    UBYTE   trmdepth;   /* "" depth */

    UBYTE   fslideupspd;
    UBYTE   fslidednspd;
    UBYTE   fportupspd; /* fx E1 (extra fine portamento up) data */
    UBYTE   fportdnspd; /* fx E2 (extra fine portamento dn) data */
    UBYTE   ffportupspd;/* fx X1 (extra fine portamento up) data */
    UBYTE   ffportdnspd;/* fx X2 (extra fine portamento dn) data */

    ULONG   hioffset;   /* last used high order of sample offset */
    UWORD   soffset;    /* last used low order of sample-offset (effect 9) */

    UBYTE   sseffect;   /* last used Sxx effect */
    UBYTE   ssdata;     /* last used Sxx data info */
    UBYTE   chanvolslide;/* last used channel volume slide */

    UBYTE   panbwave;   /* current panbrello waveform */
    UBYTE   panbpos;    /* current panbrello position */
    SBYTE   panbspd;    /* "" speed */
    UBYTE   panbdepth;  /* "" depth */

    UWORD   newsamp;    /* set to 1 upon a sample / inst change */
    UBYTE   voleffect;  /* Volume Column Effect Memory as used by IT */
    UBYTE   voldata;    /* Volume Column Data Memory */

    SWORD   pat_reppos; /* patternloop position */
    UWORD   pat_repcnt; /* times to loop */
} MP_CONTROL;

/* Used by NNA only player (audio control.  AUDTMP is used for full effects
   control). */
typedef struct MP_VOICE {
    struct MP_CHANNEL   main;

    ENVPR   venv;
    ENVPR   penv;
    ENVPR   cenv;

    UWORD   avibpos;    /* autovibrato pos */
    UWORD   aswppos;    /* autovibrato sweep pos */

    ULONG   totalvol;   /* total volume of channel (before global mixings) */

    int    mflag;
    SWORD   masterchn;
    UWORD   masterperiod;

    MP_CONTROL* master; /* index of "master" effects channel */
} MP_VOICE;

/*========== Loaders */

typedef struct MLOADER {
    struct MLOADER*     next;
    const CHAR* type;
    const CHAR* version;
    int  (*Init)(void);
    int  (*Test)(void);
    int  (*Load)(int);
    void  (*Cleanup)(void);
    CHAR* (*LoadTitle)(void);
} MLOADER;

/* internal loader variables */
extern MREADER* modreader;
extern MODULE  of;                  /* static unimod loading space */
extern const UWORD finetune[16];
extern const UWORD npertab[7*OCTAVE];/* used by the original MOD loaders */

extern SBYTE   remap[UF_MAXCHAN];   /* for removing empty channels */
extern UBYTE*  poslookup;           /* lookup table for pattern jumps after
                                       blank pattern removal */
extern UWORD   poslookupcnt;
extern UWORD*  origpositions;

extern int    filters;             /* resonant filters in use */
extern UBYTE   activemacro;         /* active midi macro number for Sxx */
extern UBYTE   filtermacros[UF_MAXMACRO];    /* midi macro settings */
extern FILTER  filtersettings[UF_MAXFILTER]; /* computed filter settings */

extern int*    noteindex;

/*========== Internal loader interface */

extern int   ReadComment(UWORD);
extern int   ReadLinedComment(UWORD,UWORD);
extern int   AllocPositions(int);
extern int   AllocPatterns(void);
extern int   AllocTracks(void);
extern int   AllocInstruments(void);
extern int   AllocSamples(void);
extern CHAR*  DupStr(const CHAR*, UWORD, int);

/* loader utility functions */
extern int*   AllocLinear(void);
extern void   FreeLinear(void);
extern int    speed_to_finetune(ULONG,int);
extern void   S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int);
extern void   S3MIT_CreateOrders(int);

/* flags for S3MIT_ProcessCmd */
#define S3MIT_OLDSTYLE  1   /* behave as old scream tracker */
#define S3MIT_IT        2   /* behave as impulse tracker */
#define S3MIT_SCREAM    4   /* enforce scream tracker specific limits */

/* used to convert c4spd to linear XM periods (IT and IMF loaders). */
extern UWORD  getlinearperiod(UWORD,ULONG);
extern ULONG  getfrequency(UWORD,ULONG);

/* loader shared data */
#define STM_NTRACKERS   3
extern const CHAR *STM_Signatures[STM_NTRACKERS];

/*========== Player interface */

extern int    Player_Init(MODULE*);
extern void   Player_Exit(MODULE*);
extern void   Player_HandleTick(void);

/*========== UnPackers */

typedef int (*MUNPACKER) (struct MREADER*,
                           void** /* unpacked data out */ ,
                           long* /* unpacked data size */ );
extern int PP20_Unpack(MREADER*, void**, long*);
extern int MMCMP_Unpack(MREADER*, void**, long*);
extern int XPK_Unpack(MREADER*, void**, long*);
extern int S404_Unpack(MREADER*, void**, long*);

/*========== Drivers */

/* max. number of handles a driver has to provide. (not strict) */
#define MAXSAMPLEHANDLES    384

/* These variables can be changed at ANY time and results will be immediate */
extern UWORD md_bpm;         /* current song / hardware BPM rate */

/* Variables below can be changed via MD_SetNumVoices at any time. However, a
   call to MD_SetNumVoicess while the driver is active will cause the sound to
   skip slightly. */
extern UBYTE md_numchn;      /* number of song + sound effects voices */
extern UBYTE md_sngchn;      /* number of song voices */
extern UBYTE md_sfxchn;      /* number of sound effects voices */
extern UBYTE md_hardchn;     /* number of hardware mixed voices */
extern UBYTE md_softchn;     /* number of software mixed voices */

/* This is for use by the hardware drivers only.  It points to the registered
   tickhandler function. */
extern MikMod_player_t md_player;

extern SWORD  MD_SampleLoad(SAMPLOAD*,int);
extern void   MD_SampleUnload(SWORD);
extern ULONG  MD_SampleSpace(int);
extern ULONG  MD_SampleLength(int,SAMPLE*);

/* uLaw conversion */
extern void unsignedtoulaw(char *,int);

/* Parameter extraction helper */
extern CHAR  *MD_GetAtom(const CHAR*, const CHAR*, int);

/* Internal software mixer stuff */
extern void VC_SetupPointers(void);
extern int  VC1_Init(void);
extern int  VC2_Init(void);

#if (MIKMOD_UNIX)
/* POSIX helper functions */
extern int MD_Access(const CHAR *);
extern int  MD_DropPrivileges(void);
#endif

/* Macro to define a missing driver, yet allowing binaries to dynamically link
   with the library without missing symbol errors */
#define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 }

/*========== Prototypes for non-MT safe versions of some public functions */

extern void _mm_registerdriver(struct MDRIVER*);
extern void _mm_registerloader(struct MLOADER*);
extern int MikMod_Active_internal(void);
extern void MikMod_DisableOutput_internal(void);
extern int  MikMod_EnableOutput_internal(void);
extern void MikMod_Exit_internal(void);
extern int  MikMod_SetNumVoices_internal(int,int);
extern void Player_Exit_internal(MODULE*);
extern void Player_Stop_internal(void);
extern int Player_Paused_internal(void);
extern void Sample_Free_internal(SAMPLE*);
extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);
extern void Voice_SetFrequency_internal(SBYTE,ULONG);
extern void Voice_SetPanning_internal(SBYTE,ULONG);
extern void Voice_SetVolume_internal(SBYTE,UWORD);
extern void Voice_Stop_internal(SBYTE);
extern int Voice_Stopped_internal(SBYTE);

extern int   VC1_PlayStart(void);
extern int   VC2_PlayStart(void);
extern void  VC1_PlayStop(void);
extern void  VC2_PlayStop(void);
extern int  VC1_SetNumVoices(void);
extern int  VC2_SetNumVoices(void);

extern MikMod_callback_t vc_callback;

#ifdef __cplusplus
}
#endif

/*========== SIMD mixing routines */
#undef HAVE_ALTIVEC
#undef HAVE_SSE2
#if defined(MIKMOD_SIMD)

#if (defined(__ppc__) || defined(__ppc64__)) && defined(__VEC__) && !(defined(__GNUC__) && (__GNUC__ < 3))
#define HAVE_ALTIVEC

#elif defined(__GNUC__) && defined(__SSE2__) /* x86 / x86_64 */
#define HAVE_SSE2

#elif defined(_MSC_VER) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64))
/* FIXME: emmintrin.h requires VC6 processor pack or VC2003+ */
#define HAVE_SSE2
/* avoid some warnings */
#pragma warning(disable:4761)
#pragma warning(disable:4391)
#pragma warning(disable:4244)

#endif /* AltiVec/SSE2 */
#endif /* MIKMOD_SIMD */

/*========== SIMD mixing helper functions =============*/

#if defined(_WIN64)
# if defined(_MSC_VER)
#  define IS_ALIGNED_16(ptr) (!((__int64)(ptr) & 15i64))
# else /* GCC, LCC, .. */
#  define IS_ALIGNED_16(ptr) (!((long long)(ptr) & 15LL))
# endif
#else /* long cast should be OK for all else */
#define IS_ALIGNED_16(ptr) (!((long)(ptr) & 15L))
#endif

/* Altivec helper function */
#if defined HAVE_ALTIVEC

#define simd_m128i vector signed int
#define simd_m128 vector float

#ifdef __GNUC__
#include <ppc_intrinsics.h>
#endif

/* Helper functions */

/* Set single float across the four values */
static inline vector float vec_mul(const vector float a, const vector float b) {
    return vec_madd(a, b, (const vector float)(0.f));
}

/* Set single float across the four values */
static inline vector float vec_load_ps1(const float *pF) {
    vector float data = vec_lde(0, pF);
    return vec_splat(vec_perm(data, data, vec_lvsl(0, pF)), 0);
}

/* Set vector to 0 */
static inline vector float vec_setzero() {
    return (vector float) (0.);
}

static inline vector signed char vec_set1_8(unsigned char splatchar) {
    vector unsigned char splatmap = vec_lvsl(0, &splatchar);
    vector unsigned char result = vec_lde(0, &splatchar);
    splatmap = vec_splat(splatmap, 0);
    return (vector signed char)vec_perm(result, result, splatmap);
}

#define PERM_A0 0x00,0x01,0x02,0x03
#define PERM_A1 0x04,0x05,0x06,0x07
#define PERM_A2 0x08,0x09,0x0A,0x0B
#define PERM_A3 0x0C,0x0D,0x0E,0x0F
#define PERM_B0 0x10,0x11,0x12,0x13
#define PERM_B1 0x14,0x15,0x16,0x17
#define PERM_B2 0x18,0x19,0x1A,0x1B
#define PERM_B3 0x1C,0x1D,0x1E,0x1F

/* Equivalent to _mm_unpacklo_epi32 */
static inline vector signed int vec_unpacklo(vector signed int a, vector signed int b) {
   return vec_perm(a, b, (vector unsigned char)(PERM_A0,PERM_A1,PERM_B0,PERM_B1));
}

/* Equivalent to _mm_srli_si128(a, 8) (without the zeroing in high part). */
static inline vector signed int vec_hiqq(vector signed int a) {
   vector signed int b = vec_splat_s32(0);
   return vec_perm(a, b, (vector unsigned char)(PERM_A2,PERM_A3,PERM_B2,PERM_B3));
}

/* vec_sra is max +15. We have to do in two times ... */
#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = vec_mul(vec_ctf(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(BITSHIFT-size)),0), mul);
#define EXTRACT_SAMPLE_SIMD_0(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-0));
#define EXTRACT_SAMPLE_SIMD_8(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-8));
#define EXTRACT_SAMPLE_SIMD_16(srce, var) var = vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(BITSHIFT+16-16));
#define PUT_SAMPLE_SIMD_W(dste, v1, v2)  vec_st(vec_packs(v1, v2), 0, dste);
#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4)  vec_st(vec_add(vec_packs((vector signed short)vec_packs(v1, v2), (vector signed short)vec_packs(v3, v4)), vec_set1_8(128)), 0, dste);
#define PUT_SAMPLE_SIMD_F(dste, v1)  vec_st(v1, 0, dste);
#define LOAD_PS1_SIMD(ptr) vec_load_ps1(ptr)

#elif defined HAVE_SSE2

#include <emmintrin.h>

/* SSE2 helper function */

static __inline __m128i mm_hiqq(const __m128i a) {
   return _mm_srli_si128(a, 8); /* get the 64bit upper part. new 64bit upper is undefined (zeroed is fine). */
}

/* 128-bit mixing macros */
#define EXTRACT_SAMPLE_SIMD(srce, var, size) var = _mm_srai_epi32(_mm_load_si128((__m128i const *)(srce)), BITSHIFT+16-size);
#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128((__m128i const *)(srce)), BITSHIFT-size)), mul);
#define EXTRACT_SAMPLE_SIMD_0(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 0)
#define EXTRACT_SAMPLE_SIMD_8(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 8)
#define EXTRACT_SAMPLE_SIMD_16(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 16)
#define PUT_SAMPLE_SIMD_W(dste, v1, v2)  _mm_store_si128((__m128i*)(dste), _mm_packs_epi32(v1, v2));
#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4)  _mm_store_si128((__m128i*)(dste), _mm_add_epi8(_mm_packs_epi16(_mm_packs_epi32(v1, v2), _mm_packs_epi32(v3, v4)), _mm_set1_epi8(128)));
#define PUT_SAMPLE_SIMD_F(dste, v1)  _mm_store_ps((float*)(dste), v1);
#define LOAD_PS1_SIMD(ptr) _mm_load_ps1(ptr)
#define simd_m128i __m128i
#define simd_m128 __m128

#endif

#if defined(HAVE_SSE2) || defined(HAVE_ALTIVEC)
/* MikMod_amalloc() returns a 16 byte aligned zero-filled
   memory in SIMD-enabled builds.
 - the returned memory can be freed with MikMod_afree()
 - the returned memory CAN NOT be realloc()'ed safely.  */
#ifdef __cplusplus
extern "C" {
#endif
void* MikMod_amalloc(size_t);
void MikMod_afree(void *);  /* frees if ptr != NULL */
#ifdef __cplusplus
}
#endif

#else /* NO SIMD */
#define MikMod_amalloc MikMod_malloc
#define MikMod_afree MikMod_free
#endif

#endif /* _MIKMOD_INTERNALS_H */

/* ex:set ts=4: */