/* 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 #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 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 #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 #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 #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 /* 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: */