/*************************************************************************************/ /*************************************************************************************/ /** **/ /** V2 module player (.v2m) **/ /** (c) Tammo 'kb' Hinrichs 2000-2008 **/ /** This file is under the Artistic License 2.0, see LICENSE.txt for details **/ /** **/ /*************************************************************************************/ /*************************************************************************************/ #ifndef V2MPLAYER_H_ #define V2MPLAYER_H_ /*************************************************************************************/ /** **/ /** Type definitions **/ /** **/ /*************************************************************************************/ #ifndef V2TYPES #define V2TYPES typedef int sInt; typedef unsigned int sUInt; typedef sInt sBool; typedef char sChar; typedef signed char sS8; typedef signed short sS16; typedef signed long sS32; typedef signed __int64 sS64; typedef unsigned char sU8; typedef unsigned short sU16; typedef unsigned long sU32; typedef unsigned __int64 sU64; typedef float sF32; typedef double sF64; #define sTRUE 1 #define sFALSE 0 template inline T sMin(const T a, const T b) { return (a inline T sMax(const T a, const T b) { return (a>b)?a:b; } template inline T sClamp(const T x, const T min, const T max) { return sMax(min,sMin(max,x)); } #endif /*************************************************************************************/ /** **/ /** V2M player class **/ /** **/ /*************************************************************************************/ class V2MPlayer { public: // init // call this instead of a constructor void Init(sU32 a_tickspersec=1000) { m_tpc=a_tickspersec; m_base.valid=0; } // opens a v2m file for playing // // a_v2mptr : ptr to v2m data // NOTE: the memory block has to remain valid // as long as the player is opened! // a_samplerate : samplerate at which the synth is operating // if this is zero, output will be disabled and // only the timing query functions will work // returns : flag if succeeded // sBool Open (const void *a_v2mptr, sU32 a_samplerate=44100); // closes player // void Close (); // starts playing // // a_time : time offset from song start in msecs // void Play (sU32 a_time=0); // stops playing // // a_fadetime : optional fade out time in msecs // void Stop (sU32 a_fadetime=0); // render call (to be used from sound thread et al) // renders samples (or silence if not playing) into buffer // // a_buffer : ptr to stereo float sample buffer (0dB=1.0f) // a_len : number of samples to render // // returns : flag if playing // void Render (sF32 *a_buffer, sU32 a_len, sBool a_add=0); // render proxy for C-style callbacks // // a_this : void ptr to instance // rest as in Render() // static void __stdcall RenderProxy(void *a_this, sF32 *a_buffer, sU32 a_len) { reinterpret_cast(a_this)->Render(a_buffer,a_len); } // returns if song is currently playing sBool IsPlaying(); sU32 GetPlayTick(); void GetChannelVU( sS32 ch, sF32 *l, sF32 *r ); #ifdef V2MPLAYER_SYNC_FUNCTIONS // Retrieves an array of timer<->song position // // a_dest: pointer to a variable which will receive the address of an array of long // values structured as following: // first long: time in ms // second long: song position (see above for a description) // format: 0xBBBBTTNN, where // BBBB is the bar number (starting at 0) // TT is the number of the 32th tick within the current bar // NN is the total number of 32th ticks a the current bar has // (32, normally, may change with different time signatures than 4/4) // ... and so on for every found position // // NOTE: it is your responsibility to free the array again. // // returns: number of found song positions // sU32 CalcPositions(sS32 **a_dest); #endif // ------------------------------------------------------------------------------------------------------ // no need to look beyond this point. // ------------------------------------------------------------------------------------------------------ private: // struct defs // General info from V2M file struct V2MBase { sBool valid; const sU8 *patchmap; const sU8 *globals; sU32 timediv; sU32 timediv2; sU32 maxtime; const sU8 *gptr; sU32 gdnum; struct Channel { sU32 notenum; const sU8 *noteptr; sU32 pcnum; const sU8 *pcptr; sU32 pbnum; const sU8 *pbptr; struct CC { sU32 ccnum; const sU8 *ccptr; } ctl[7]; } chan[16]; const char *speechdata; const char *speechptrs[256]; }; // player state struct PlayerState { enum { OFF, STOPPED, PLAYING, } state; sU32 time; sU32 nexttime; const sU8 *gptr; sU32 gnt; sU32 gnr; sU32 usecs; sU32 num; sU32 den; sU32 tpq; sU32 bar; sU32 beat; sU32 tick; struct Channel { const sU8 *noteptr; sU32 notenr; sU32 notent; sU8 lastnte; sU8 lastvel; const sU8 *pcptr; sU32 pcnr; sU32 pcnt; sU8 lastpc; const sU8 *pbptr; sU32 pbnr; sU32 pbnt; sU8 lastpb0; sU8 lastpb1; struct CC { const sU8 *ccptr; sU32 ccnt; sU32 ccnr; sU8 lastcc; } ctl[7]; } chan[16]; sU32 cursmpl; sU32 smpldelta; sU32 smplrem; sU32 tdif; }; // \o/ sU8 m_synth[3*1024*1024]; // TODO: keep me uptodate or use "new" // member variables sU32 m_tpc; V2MBase m_base; PlayerState m_state; sU32 m_samplerate; sS32 m_timeoffset; sU8 m_midibuf[4096]; sF32 m_fadeval; sF32 m_fadedelta; // internal methods sBool InitBase(const void *a_v2m); // inits base struct from v2m void Reset(); // resets player, inits synth void Tick(); // one midi player tick }; #endif