XFuXMPlayer.cpp Source File

Main Page Class Hierarchy Alphabetical List Compound List File List Compound Members File Members Related Pages

# XFuXMPlayer.cpp

Go to the documentation of this file.

    00001 /*! \file
    00002  * X-Forge Util <br>
    00003  * Copyright 2000-2003 Fathammer Ltd
    00004  *
    00005  * \brief XM player.
    00006  * \todo doxygen comments
    00007  * \todo Panning envelope support on "key off"
    00008  * \todo Random waveform support for vibrato and tremolo
    00009  * \todo Set glissando control -command
    00010  *
    00011  * $Id: XFuXMPlayer.cpp,v 1.55 2003/10/10 11:34:51 toni Exp $
    00012  * $Date: 2003/10/10 11:34:51 $
    00013  * $Revision: 1.55 $
    00014  */
    00015
    00016 #include <stdlib.h> // \ needed for
    00017 #include <stdarg.h> // / va_args
    00018 #include <xfcore/XFcCore.h>
    00019 #include <xfcore/XFcAudioFlags.h>
    00020 #include <xfcore/XFcLinkedList.h>
    00021 #include <xfutil/XFuXMPlayer.h>
    00022 #include <xfutil/XFuXMPlayer_internal.h>
    00023 #include <xfutil/XFuXMPlayerEventHandler.h>
    00024
    00025
    00026 const static INT32 linearFrequencyTable[768] =
    00027 {
    00028     535232,534749,534266,533784,533303,532822,532341,531861,
    00029     531381,530902,530423,529944,529466,528988,528511,528034,
    00030     527558,527082,526607,526131,525657,525183,524709,524236,
    00031     523763,523290,522818,522346,521875,521404,520934,520464,
    00032     519994,519525,519057,518588,518121,517653,517186,516720,
    00033     516253,515788,515322,514858,514393,513929,513465,513002,
    00034     512539,512077,511615,511154,510692,510232,509771,509312,
    00035     508852,508393,507934,507476,507018,506561,506104,505647,
    00036     505191,504735,504280,503825,503371,502917,502463,502010,
    00037     501557,501104,500652,500201,499749,499298,498848,498398,
    00038     497948,497499,497050,496602,496154,495706,495259,494812,
    00039     494366,493920,493474,493029,492585,492140,491696,491253,
    00040     490809,490367,489924,489482,489041,488600,488159,487718,
    00041     487278,486839,486400,485961,485522,485084,484647,484210,
    00042     483773,483336,482900,482465,482029,481595,481160,480726,
    00043     480292,479859,479426,478994,478562,478130,477699,477268,
    00044     476837,476407,475977,475548,475119,474690,474262,473834,
    00045     473407,472979,472553,472126,471701,471275,470850,470425,
    00046     470001,469577,469153,468730,468307,467884,467462,467041,
    00047     466619,466198,465778,465358,464938,464518,464099,463681,
    00048     463262,462844,462427,462010,461593,461177,460760,460345,
    00049     459930,459515,459100,458686,458272,457859,457446,457033,
    00050     456621,456209,455797,455386,454975,454565,454155,453745,
    00051     453336,452927,452518,452110,451702,451294,450887,450481,
    00052     450074,449668,449262,448857,448452,448048,447644,447240,
    00053     446836,446433,446030,445628,445226,444824,444423,444022,
    00054     443622,443221,442821,442422,442023,441624,441226,440828,
    00055     440430,440033,439636,439239,438843,438447,438051,437656,
    00056     437261,436867,436473,436079,435686,435293,434900,434508,
    00057     434116,433724,433333,432942,432551,432161,431771,431382,
    00058     430992,430604,430215,429827,429439,429052,428665,428278,
    00059     427892,427506,427120,426735,426350,425965,425581,425197,
    00060     424813,424430,424047,423665,423283,422901,422519,422138,
    00061     421757,421377,420997,420617,420237,419858,419479,419101,
    00062     418723,418345,417968,417591,417214,416838,416462,416086,
    00063     415711,415336,414961,414586,414212,413839,413465,413092,
    00064     412720,412347,411975,411604,411232,410862,410491,410121,
    00065     409751,409381,409012,408643,408274,407906,407538,407170,
    00066     406803,406436,406069,405703,405337,404971,404606,404241,
    00067     403876,403512,403148,402784,402421,402058,401695,401333,
    00068     400970,400609,400247,399886,399525,399165,398805,398445,
    00069     398086,397727,397368,397009,396651,396293,395936,395579,
    00070     395222,394865,394509,394153,393798,393442,393087,392733,
    00071     392378,392024,391671,391317,390964,390612,390259,389907,
    00072     389556,389204,388853,388502,388152,387802,387452,387102,
    00073     386753,386404,386056,385707,385359,385012,384664,384317,
    00074     383971,383624,383278,382932,382587,382242,381897,381552,
    00075     381208,380864,380521,380177,379834,379492,379149,378807,
    00076     378466,378124,377783,377442,377102,376762,376422,376082,
    00077     375743,375404,375065,374727,374389,374051,373714,373377,
    00078     373040,372703,372367,372031,371695,371360,371025,370690,
    00079     370356,370022,369688,369355,369021,368688,368356,368023,
    00080     367691,367360,367028,366697,366366,366036,365706,365376,
    00081     365046,364717,364388,364059,363731,363403,363075,362747,
    00082     362420,362093,361766,361440,361114,360788,360463,360137,
    00083     359813,359488,359164,358840,358516,358193,357869,357547,
    00084     357224,356902,356580,356258,355937,355616,355295,354974,
    00085     354654,354334,354014,353695,353376,353057,352739,352420,
    00086     352103,351785,351468,351150,350834,350517,350201,349885,
    00087     349569,349254,348939,348624,348310,347995,347682,347368,
    00088     347055,346741,346429,346116,345804,345492,345180,344869,
    00089     344558,344247,343936,343626,343316,343006,342697,342388,
    00090     342079,341770,341462,341154,340846,340539,340231,339924,
    00091     339618,339311,339005,338700,338394,338089,337784,337479,
    00092     337175,336870,336566,336263,335959,335656,335354,335051,
    00093     334749,334447,334145,333844,333542,333242,332941,332641,
    00094     332341,332041,331741,331442,331143,330844,330546,330247,
    00095     329950,329652,329355,329057,328761,328464,328168,327872,
    00096     327576,327280,326985,326690,326395,326101,325807,325513,
    00097     325219,324926,324633,324340,324047,323755,323463,323171,
    00098     322879,322588,322297,322006,321716,321426,321136,320846,
    00099     320557,320267,319978,319690,319401,319113,318825,318538,
    00100     318250,317963,317676,317390,317103,316817,316532,316246,
    00101     315961,315676,315391,315106,314822,314538,314254,313971,
    00102     313688,313405,313122,312839,312557,312275,311994,311712,
    00103     311431,311150,310869,310589,310309,310029,309749,309470,
    00104     309190,308911,308633,308354,308076,307798,307521,307243,
    00105     306966,306689,306412,306136,305860,305584,305308,305033,
    00106     304758,304483,304208,303934,303659,303385,303112,302838,
    00107     302565,302292,302019,301747,301475,301203,300931,300660,
    00108     300388,300117,299847,299576,299306,299036,298766,298497,
    00109     298227,297958,297689,297421,297153,296884,296617,296349,
    00110     296082,295815,295548,295281,295015,294749,294483,294217,
    00111     293952,293686,293421,293157,292892,292628,292364,292100,
    00112     291837,291574,291311,291048,290785,290523,290261,289999,
    00113     289737,289476,289215,288954,288693,288433,288173,287913,
    00114     287653,287393,287134,286875,286616,286358,286099,285841,
    00115     285583,285326,285068,284811,284554,284298,284041,283785,
    00116     283529,283273,283017,282762,282507,282252,281998,281743,
    00117     281489,281235,280981,280728,280475,280222,279969,279716,
    00118     279464,279212,278960,278708,278457,278206,277955,277704,
    00119     277453,277203,276953,276703,276453,276204,275955,275706,
    00120     275457,275209,274960,274712,274465,274217,273970,273722,
    00121     273476,273229,272982,272736,272490,272244,271999,271753,
    00122     271508,271263,271018,270774,270530,270286,270042,269798,
    00123     269555,269312,269069,268826,268583,268341,268099,267857
    00124 };
    00125
    00126
    00127 #define ABS(x) (((x) < 0) ? -(x) : (x))
    00128
    00129 #define interpolateLinear8(ch, val1, val2) \
    00130     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00131     \
    00132     if ((ch.mPointer + FP_VALUE) < ch.mLength) \
    00133         val2 = *((INT8 *)ch.mOffset + ((ch.mPointer + FP_VALUE) >> FP_BITS)); \
    00134     else \
    00135         val2 = 0;
    00136
    00137
    00138 #define interpolateLinear16(ch, val1, val2) \
    00139     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00140     \
    00141     if ((ch.mPointer + FP_VALUE) < ch.mLength) \
    00142         val2 = *((INT16 *)ch.mOffset + ((ch.mPointer + FP_VALUE) >> FP_BITS)); \
    00143     else \
    00144         val2 = 0;
    00145
    00146
    00147 #define interpolateLinearForwardLoop8(ch, val1, val2, temp) \
    00148     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00149     \
    00150     temp = (ch.mPointer + FP_VALUE); \
    00151     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00152         temp = ch.mLoopStart + (temp - (ch.mLoopEnd + FP_VALUE)); \
    00153     \
    00154     val2 = *((INT8 *)ch.mOffset + (temp >> FP_BITS));
    00155
    00156
    00157 #define interpolateLinearForwardLoop16(ch, val1, val2, temp) \
    00158     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00159     \
    00160     temp = (ch.mPointer + FP_VALUE); \
    00161     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00162         temp = ch.mLoopStart + (temp - (ch.mLoopEnd + FP_VALUE)); \
    00163     \
    00164     val2 = *((INT16 *)ch.mOffset + (temp >> FP_BITS));
    00165
    00166
    00167 #define interpolateLinearBidirectionalLoop8(ch, val1, val2, temp) \
    00168     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00169     \
    00170     temp = (ch.mPointer + FP_VALUE); \
    00171     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00172         temp = ch.mLoopEnd - (temp - (ch.mLoopEnd + FP_VALUE)); \
    00173     \
    00174     val2 = *((INT8 *)ch.mOffset + (temp >> FP_BITS)); \
    00175
    00176
    00177 #define interpolateLinearBidirectionalLoop16(ch, val1, val2, temp) \
    00178     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
    00179     \
    00180     temp = (ch.mPointer + FP_VALUE); \
    00181     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00182         temp = ch.mLoopEnd - (temp - (ch.mLoopEnd + FP_VALUE)); \
    00183     \
    00184     val2 = *((INT16 *)ch.mOffset + (temp >> FP_BITS));
    00185
    00186
    00187 #define addPointer(ch) \
    00188     ch.mPointer += ch.mSpeed; \
    00189     if (ch.mPointer > (ch.mLength - FP_VALUE)) \
    00190         ch.mIsSample = 0;
    00191
    00192
    00193 #define addPointerForwardLoop(ch) \
    00194     ch.mPointer += ch.mSpeed; \
    00195     if ((ch.mPointer >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00196         ch.mPointer = ch.mLoopStart + (ch.mPointer - (ch.mLoopEnd + FP_VALUE));
    00197
    00198
    00199 #define addPointerBidirectionalLoop(ch) \
    00200     if (ch.mDirection == 1) \
    00201     { \
    00202         ch.mPointer += ch.mSpeed; \
    00203         \
    00204         if ((ch.mPointer >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
    00205         { \
    00206             ch.mDirection = -1; \
    00207             ch.mPointer = ch.mLoopEnd - (ch.mPointer - (ch.mLoopEnd + FP_VALUE)); \
    00208         } \
    00209     } \
    00210     else \
    00211     { \
    00212         ch.mPointer -= ch.mSpeed; \
    00213         \
    00214         if ((ch.mPointer >> FP_BITS) < (ch.mLoopStart >> FP_BITS)) \
    00215         { \
    00216             ch.mDirection = 1; \
    00217             ch.mPointer = ch.mLoopStart + (ch.mLoopStart - ch.mPointer); \
    00218         } \
    00219     }
    00220
    00221
    00222 //#define OUTPUT_XM_INFO
    00223
    00224 #ifdef OUTPUT_XM_INFO
    00225 static const CHAR *notes[12] =
    00226     {"C-","C#","D-","D#","E-","F-","F#","G-","G#","A-","A#","B-"};
    00227 #endif // OUTPUT_XM_INFO
    00228
    00229
    00230 void XFuXMPlayer::debugPrint(XFcFile *aTextout, CHAR *aFmt, ...)
    00231 {
    00232 #if !defined(XFC_PLATFORM_EPOC) && !defined(XFC_PLATFORM_PALM)
    00233     if (aTextout != NULL)
    00234     {
    00235         va_list ap;
    00236         static CHAR buffer[10240];
    00237         va_start(ap, aFmt);
    00238         vsprintf(buffer, aFmt, ap);
    00239         aTextout->write(buffer, 1, XFcStringToolkit::getLength(buffer));
    00240         va_end(ap);
    00241     }
    00242 #endif // XFC_PLATFORM_EPOC
    00243 }
    00244
    00245
    00246 void XFuXMPlayer::dumpSongParameters(XFcFile *aTextout)
    00247 {
    00248     INT i = 0, x;
    00249
    00250     debugPrint(aTextout, "\n\nParameters for current mSong. \n\n");
    00251     debugPrint(aTextout, "song length: %d\n", mSong.mSongLength);
    00252     debugPrint(aTextout, "song restart: %d\n", mSong.mRestartPosition);
    00253     debugPrint(aTextout, "order: ");
    00254
    00255     for (i = 0; i < mSong.mSongLength; i++)
    00256         debugPrint(aTextout, "%d ", mSong.mOrderTable[i]);
    00257
    00258     debugPrint(aTextout, "\n");
    00259     debugPrint(aTextout, "nof patterns: %d\n", mSong.mNbPatterns);
    00260     debugPrint(aTextout, "nof channels: %d\n", mSong.mNbChannels);
    00261     debugPrint(aTextout, "nof instrument: %d\n", mSong.mNbInstruments);
    00262     debugPrint(aTextout, "tempo: %d\n", mSong.mTempo);
    00263     debugPrint(aTextout, "bpm: %d\n", mSong.mBpm);
    00264     debugPrint(aTextout, "\nmInstruments: \n");
    00265
    00266     for (i = 0; i < mSong.mNbInstruments; i++)
    00267     {
    00268         XFuXMInstrument &ins = mInstruments[i];
    00269
    00270         debugPrint(aTextout, "\ninstr %02X \n", i);
    00271
    00272         debugPrint(aTextout, "is vibrato? %d \n", ins.mIsVibrato);
    00273         debugPrint(aTextout, "vibratoType: %d \n", ins.mVibratoType);
    00274         debugPrint(aTextout, "vibratoSweep: %d \n", ins.mVibratoSweep);
    00275         debugPrint(aTextout, "vibratoDepth: %d \n", ins.mVibratoDepth);
    00276         debugPrint(aTextout, "vibratoRate: %d \n", ins.mVibratoRate);
    00277
    00278         debugPrint(aTextout, "\nvolume envelope: \n");
    00279         debugPrint(aTextout, "  fadeout: %d \n", ins.mVolumeFadeout);
    00280         debugPrint(aTextout, "  end point: %d\n", ins.mVolEnvEnd);
    00281         debugPrint(aTextout, "  type: %d\n", ins.mVolEnvType);
    00282         debugPrint(aTextout, "  on? %d\n", (ins.mVolEnvType & ENVELOPE_ON));
    00283         debugPrint(aTextout, "  sustain? %d\n",
    00284                    (ins.mVolEnvType & ENVELOPE_SUSTAIN));
    00285         debugPrint(aTextout, "  sustain point: %d\n", (ins.mVolEnvSustain));
    00286         debugPrint(aTextout, "  loop? %d\n", (ins.mVolEnvType & ENVELOPE_LOOP));
    00287         debugPrint(aTextout, "  loop start: %d\n", ins.mVolEnvLoopStart);
    00288         debugPrint(aTextout, "  loop end: %d\n", ins.mVolEnvLoopEnd);
    00289         debugPrint(aTextout, "  envelope: ");
    00290
    00291         for (x = 0; x < ins.mVolEnvEnd; x++)
    00292             debugPrint(aTextout,"%2.2f ", ins.mVolumeEnvelope[x]);
    00293
    00294         debugPrint(aTextout, "\n");
    00295         debugPrint(aTextout, "\npanning envelope: \n");
    00296         debugPrint(aTextout, "  on? %d\n", (ins.mPanEnvType & ENVELOPE_ON));
    00297         debugPrint(aTextout, "  loop? %d\n", (ins.mPanEnvType & ENVELOPE_LOOP));
    00298         debugPrint(aTextout, "  loop start: %d\n", ins.mPanEnvLoopStart);
    00299         debugPrint(aTextout, "  loop end: %d\n", ins.mPanEnvLoopEnd);
    00300         debugPrint(aTextout, "  envelope: ");
    00301
    00302         for (x = 0; x < ins.mPanEnvEnd; x++)
    00303             debugPrint(aTextout, "%d ", ins.mPanningEnvelope[x]);
    00304
    00305         debugPrint(aTextout,"\n-----\n");
    00306     }
    00307 }
    00308
    00309
    00310 INT XFuXMPlayer::loadXM(const CHAR *aFilename, XFcFile *aTextout)
    00311 {
    00312     XFcFile *f;
    00313
    00314     INT i, j, k, ii;
    00315     FLOAT32 y1, y2, dx;
    00316     INT xx, x1, x2;
    00317
    00318     XFuXMFormatInstrumentHeader xmInstrumentHeader;
    00319     XFuXMFormatInstrument xmInstrument;
    00320     XFuXMFormatSample xmSample;
    00321
    00322     debugPrint(aTextout, "Fathammer XM-player debug file.\n");
    00323     debugPrint(aTextout, "Opening %s.\n", aFilename);
    00324
    00325     f = XFcFile::open(aFilename, "rb");
    00326     if (f == 0) {
    00327         debugPrint(aTextout, "error opening file.\n");
    00328         if (aTextout != NULL) aTextout->close();
    00329         return 1;
    00330     }
    00331
    00332     debugPrint(aTextout, "opened.\n");
    00333
    00334     debugPrint(aTextout, "reading header...\n\n");
    00335     f->read(mXMHeader.mIdString, 17, sizeof(UINT8));
    00336     mXMHeader.mIdString[17] = 0;
    00337
    00338     // Check id string
    00339     INT wrongId = XFcStringToolkit::compare((const CHAR *)mXMHeader.mIdString, "Extended Module: ");
    00340     if (wrongId) return 1;
    00341
    00342     f->read(mXMHeader.mModuleName, 20, sizeof(UINT8));
    00343     mXMHeader.mModuleName[20] = 0;
    00344
    00345     // Check $1A byte
    00346     f->readUINT8(mXMHeader.mH1A);
    00347     if (mXMHeader.mH1A != 0x1A) return 1;
    00348
    00349     f->read(mXMHeader.mTrackerName, 20, sizeof(UINT8));
    00350     mXMHeader.mTrackerName[20] = 0;
    00351
    00352     f->readUINT16(mXMHeader.mVersion);
    00353
    00354     f->readUINT32(mXMHeader.mHeaderSize);
    00355
    00356     f->readUINT16(mXMHeader.mSongLength);
    00357     f->readUINT16(mXMHeader.mRestartPosition);
    00358     f->readUINT16(mXMHeader.mNbChannels);
    00359     f->readUINT16(mXMHeader.mNbPatterns);
    00360     f->readUINT16(mXMHeader.mNbInstruments);
    00361
    00362     f->readUINT16(mXMHeader.mFlags);
    00363
    00364     f->readUINT16(mXMHeader.mTempo);
    00365     f->readUINT16(mXMHeader.mBpm);
    00366
    00367     f->read(mXMHeader.mOrderTable, 256, sizeof(UINT8));
    00368
    00369     debugPrint(aTextout, "id string: %s\n", mXMHeader.mIdString);
    00370     debugPrint(aTextout, "module name: %s\n", mXMHeader.mModuleName);
    00371     debugPrint(aTextout, "h1A: %d\n", mXMHeader.mH1A);
    00372     debugPrint(aTextout, "tracker name: %s\n", mXMHeader.mTrackerName);
    00373     debugPrint(aTextout, "tracker version: %d\n", mXMHeader.mVersion);
    00374     debugPrint(aTextout, "header size: %d\n", mXMHeader.mHeaderSize);
    00375     debugPrint(aTextout, "song length: %d\n", mXMHeader.mSongLength);
    00376     debugPrint(aTextout, "restart pos: %d\n", mXMHeader.mRestartPosition);
    00377     debugPrint(aTextout, "nof mChannels: %d\n", mXMHeader.mNbChannels);
    00378     debugPrint(aTextout, "nof patterns: %d\n", mXMHeader.mNbPatterns);
    00379     debugPrint(aTextout, "nof instrument: %d\n", mXMHeader.mNbInstruments);
    00380     debugPrint(aTextout, "flags: %d\n", mXMHeader.mFlags);
    00381     debugPrint(aTextout, "tempo: %d\n", mXMHeader.mTempo);
    00382     debugPrint(aTextout, "bpm: %d\n", mXMHeader.mBpm);
    00383     debugPrint(aTextout, "ordertable: \n");
    00384
    00385     // Allocate memory for order list
    00386     mSong.mOrderTable = new UINT8[mXMHeader.mSongLength];
    00387     memset(mSong.mOrderTable, 0, mXMHeader.mSongLength * sizeof(UINT8));
    00388
    00389     for (i = 0; i < mXMHeader.mSongLength; i++)
    00390     {
    00391         debugPrint(aTextout, "%2X->%2X\n", i, mXMHeader.mOrderTable[i]);
    00392         mSong.mOrderTable[i] = mXMHeader.mOrderTable[i];
    00393     }
    00394
    00395     // Save song header
    00396     mSong.mNbChannels = mXMHeader.mNbChannels;
    00397     mSong.mNbPatterns = mXMHeader.mNbPatterns;
    00398     mSong.mNbInstruments = mXMHeader.mNbInstruments;
    00399     mSong.mSongLength = mXMHeader.mSongLength;
    00400     mSong.mRestartPosition = mXMHeader.mRestartPosition;
    00401     mSong.mBpm = mXMHeader.mBpm;
    00402     mSong.mTempo = mXMHeader.mTempo;
    00403
    00404     // Allocate memory for mChannels
    00405     mChannels = new XFuXMChannel[mSong.mNbChannels];
    00406     memset(mChannels, 0, mSong.mNbChannels * sizeof(XFuXMChannel));
    00407
    00408     // Read pattern headers and pattern data
    00409     debugPrint(aTextout, "\npatterns:\n\n");
    00410
    00411     // Allocate memory for pattern headers
    00412     mXMPatternHeaders = new XFuXMFormatPatternHeader[mXMHeader.mNbPatterns];
    00413     memset(mXMPatternHeaders, 0, mXMHeader.mNbPatterns * sizeof(XFuXMFormatPatternHeader));
    00414
    00415     // Allocate memory for pattern data blocks
    00416     mPatternData = new XFuXMPattern[mXMHeader.mNbPatterns];
    00417     memset(mPatternData, 0, mXMHeader.mNbPatterns * sizeof(XFuXMPattern));
    00418
    00419     for (i = 0; i < mXMHeader.mNbPatterns; i++)
    00420     {
    00421         debugPrint(aTextout, "pattern %d \n", i);
    00422
    00423         f->readUINT32(mXMPatternHeaders[i].mHeaderLength);
    00424         f->readUINT8(mXMPatternHeaders[i].mPackingType);
    00425         f->readUINT16(mXMPatternHeaders[i].mNbRows);
    00426         f->readUINT16(mXMPatternHeaders[i].mSize);
    00427
    00428         debugPrint(aTextout, "header length: %d \n", mXMPatternHeaders[i].mHeaderLength);
    00429         debugPrint(aTextout, "packing type: %d \n", mXMPatternHeaders[i].mPackingType);
    00430         debugPrint(aTextout, "nof rows: %d \n", mXMPatternHeaders[i].mNbRows);
    00431         debugPrint(aTextout, "size: %d \n\n", mXMPatternHeaders[i].mSize);
    00432
    00433         if (mXMPatternHeaders[i].mSize > 0)
    00434         {
    00435             // Allocate memory for actual pattern data
    00436             mPatternData[i].mData = new UINT8[mXMPatternHeaders[i].mSize];
    00437             mPatternData[i].mRows = new UINT32[mXMPatternHeaders[i].mNbRows];
    00438             f->read(mPatternData[i].mData, mXMPatternHeaders[i].mSize, 1);
    00439
    00440             UINT8 b = 0;
    00441             UINT32 p = 0;
    00442             for (j = 0; j < mXMPatternHeaders[i].mNbRows; j++)
    00443             {
    00444                 mPatternData[i].mRows[j] = p;
    00445
    00446                 for (k = 0; k < mSong.mNbChannels; k++)
    00447                 {
    00448                     b = *(mPatternData[i].mData + p++);
    00449
    00450                     if ((b & 128) == 128) {
    00451                         // Packed atom
    00452                         if ((b & 1) == 1) p++;
    00453                         if ((b & 2) == 2) p++;
    00454                         if ((b & 4) == 4) p++;
    00455                         if ((b & 8) == 8) p++;
    00456                         if ((b & 16) == 16) p++;
    00457                     }
    00458                     else
    00459                     {
    00460                         // Normal atom
    00461                         p += 4;
    00462                     }
    00463                 }
    00464             }
    00465         }
    00466     }
    00467
    00468     // Allocate memory for mInstruments
    00469     mInstruments = new XFuXMInstrument[mXMHeader.mNbInstruments];
    00470     memset(mInstruments, 0, mXMHeader.mNbInstruments * sizeof(XFuXMInstrument));
    00471
    00472     // Read mInstruments
    00473     debugPrint(aTextout, "mInstruments \n\n");
    00474     for (i = 0; i < mXMHeader.mNbInstruments; i++)
    00475     {
    00476         debugPrint(aTextout, "instrument %02x \n", i);
    00477
    00478         XFuXMInstrument &ins = mInstruments[i];
    00479
    00480         memset(&xmInstrumentHeader, 0, sizeof(XFuXMFormatInstrumentHeader));
    00481
    00482         f->readUINT32(xmInstrumentHeader.mSize);
    00483
    00484         f->read(xmInstrumentHeader.mInstrumentName, 22, sizeof(UINT8));
    00485         xmInstrumentHeader.mInstrumentName[22] = 0;
    00486
    00487         f->readUINT8(xmInstrumentHeader.mType);
    00488         f->readUINT16(xmInstrumentHeader.mNbSamples);
    00489
    00490         ins.mNbSamples = xmInstrumentHeader.mNbSamples;
    00491
    00492         debugPrint(aTextout, "size: %d \n", xmInstrumentHeader.mSize);
    00493         debugPrint(aTextout, "name: %s \n", xmInstrumentHeader.mInstrumentName);
    00494         debugPrint(aTextout, "type: %d \n", xmInstrumentHeader.mType);
    00495         debugPrint(aTextout, "nof samples: %d \n",
    00496                    xmInstrumentHeader.mNbSamples);
    00497
    00498         // sizeof(xmInstrumentHeader) could return an ALIGNED value
    00499         INT32 skip = xmInstrumentHeader.mSize - 29;
    00500
    00501         if (xmInstrumentHeader.mNbSamples > 0)
    00502         {
    00503             memset(&xmInstrument, 0, sizeof(XFuXMFormatInstrument));
    00504
    00505             f->readUINT32(xmInstrument.mSampleHeaderSize);
    00506             f->read(xmInstrument.mKeyboard, 96, sizeof(UINT8));
    00507             f->read(xmInstrument.mVolumeEnvelope, 24, sizeof(UINT16));
    00508             f->read(xmInstrument.mPanningEnvelope, 24, sizeof(UINT16));
    00509             f->readUINT8(xmInstrument.mNbVolEnvPoints);
    00510             f->readUINT8(xmInstrument.mNbPanEnvPoints);
    00511             f->readUINT8(xmInstrument.mVolEnvSustain);
    00512             f->readUINT8(xmInstrument.mVolEnvLoopStart);
    00513             f->readUINT8(xmInstrument.mVolEnvLoopEnd);
    00514             f->readUINT8(xmInstrument.mPanEnvSustain);
    00515             f->readUINT8(xmInstrument.mPanEnvLoopStart);
    00516             f->readUINT8(xmInstrument.mPanEnvLoopEnd);
    00517             f->readUINT8(xmInstrument.mVolEnvType);
    00518             f->readUINT8(xmInstrument.mPanEnvType);
    00519
    00520             f->readUINT8(xmInstrument.mVibratoType);
    00521             f->readUINT8(xmInstrument.mVibratoSweep);
    00522             f->readUINT8(xmInstrument.mVibratoDepth);
    00523             f->readUINT8(xmInstrument.mVibratoRate);
    00524
    00525             f->readUINT16(xmInstrument.mVolumeFadeout);
    00526
    00527             f->readUINT16(xmInstrument.mReserved);
    00528
    00529             // sizeof(xmInstrument) could return an ALIGNED value
    00530             skip -= 214;
    00531             f->seek(skip, SEEK_CUR);
    00532
    00533             // Allocate memory for samples in instrument
    00534             ins.mSamples = new XFuXMSample[xmInstrumentHeader.mNbSamples];
    00535             memset(ins.mSamples, 0, xmInstrumentHeader.mNbSamples * sizeof(XFuXMSample));
    00536
    00537             for (j = 0; j < xmInstrumentHeader.mNbSamples; j++)
    00538             {
    00539                 XFuXMSample &smp = ins.mSamples[j];
    00540
    00541                 memset(&xmSample, 0, sizeof(XFuXMFormatSample));
    00542
    00543                 f->readUINT32(xmSample.mSampleLength);
    00544                 f->readUINT32(xmSample.mLoopStart);
    00545                 f->readUINT32(xmSample.mLoopLength);
    00546                 f->readUINT8(xmSample.mVolume);
    00547                 f->readINT8(xmSample.mFinetune);
    00548                 f->readUINT8(xmSample.mType);
    00549                 f->readUINT8(xmSample.mPan);
    00550                 f->readINT8(xmSample.mRelativeNote);
    00551                 f->readUINT8(xmSample.mReserved);
    00552
    00553                 f->read(xmSample.mSampleName, 22, sizeof(UINT8));
    00554                 xmSample.mSampleName[22] = 0;
    00555
    00556                 debugPrint(aTextout, "Allocating %d bytes for sample %02X in "
    00557                            "instrument %02X\n", xmSample.mSampleLength, j, i);
    00558                 debugPrint(aTextout, "sample length %d \n", xmSample.mSampleLength);
    00559                 debugPrint(aTextout, "loop start %d \n", xmSample.mLoopStart);
    00560                 debugPrint(aTextout, "loop length %d \n", xmSample.mLoopLength);
    00561                 debugPrint(aTextout, "volume %d \n", xmSample.mVolume);
    00562                 debugPrint(aTextout, "finetune %d \n", xmSample.mFinetune);
    00563                 debugPrint(aTextout, "type %d \n", xmSample.mType);
    00564                 debugPrint(aTextout, "  loop fwd? %d\n", (xmSample.mType & LOOP_FORWARD) ? 1 : 0);
    00565                 debugPrint(aTextout, "  loop pingpong? %d\n",
    00566                     (xmSample.mType & LOOP_PINGPONG) ? 1 : 0);
    00567                 debugPrint(aTextout, "  16 bit? %d\n",
    00568                     (xmSample.mType & XMFORMAT_SAMPLE_16BIT) ? 1 : 0);
    00569                 debugPrint(aTextout, "pan %d \n", xmSample.mPan);
    00570                 debugPrint(aTextout, "relative note %d \n", xmSample.mRelativeNote);
    00571                 debugPrint(aTextout, "sample name %s \n", xmSample.mSampleName);
    00572
    00573                 smp.mSize = xmSample.mSampleLength;
    00574                 smp.mVolume = xmSample.mVolume;
    00575                 smp.mPan = xmSample.mPan;
    00576                 smp.mLoopForward = (UINT8)((xmSample.mType & LOOP_FORWARD) ? 1 : 0);
    00577                 smp.mLoopPingpong = (UINT8)((xmSample.mType & LOOP_PINGPONG) ? 1 : 0);
    00578                 smp.m16Bit = (UINT8)((xmSample.mType & XMFORMAT_SAMPLE_16BIT) ? 1 : 0);
    00579                 smp.mLoopStart = xmSample.mLoopStart;
    00580                 smp.mLoopEnd = xmSample.mLoopStart + xmSample.mLoopLength - 1;
    00581
    00582                 if (smp.mLoopStart == smp.mLoopEnd)
    00583                 {
    00584                     smp.mLoopPingpong = 0;
    00585                     smp.mLoopForward = 0;
    00586                 }
    00587
    00588                 smp.mRelativeNote = xmSample.mRelativeNote;
    00589                 smp.mFinetune = xmSample.mFinetune;
    00590             }
    00591
    00592             // Read samples
    00593             for (j = 0; j < xmInstrumentHeader.mNbSamples; j++)
    00594             {
    00595                 XFuXMSample &smp = ins.mSamples[j];
    00596
    00597                 if (smp.mSize > 0)
    00598                 {
    00599                     smp.mOffset = new INT8[smp.mSize];
    00600                     memset((INT8 *)smp.mOffset, 0, smp.mSize * sizeof(INT8));
    00601
    00602                     if (smp.mOffset == NULL)
    00603                     {
    00604                         debugPrint(aTextout, "! Memory allocation for sample "
    00605                                    "%02X in instrument %02X failed \n", j, i);
    00606                         return 1;
    00607                     }
    00608
    00609                     debugPrint(aTextout, "Reading sample \n");
    00610                     f->read((INT8 *)smp.mOffset, smp.mSize, 1);
    00611
    00612                     if (smp.m16Bit)
    00613                     {
    00614                         INT16 os, ns;
    00615                         INT16 *temp = (INT16 *)smp.mOffset;
    00616                         os = 0;
    00617
    00618                         smp.mSize >>= 1;
    00619                         smp.mLoopStart >>= 1;
    00620                         smp.mLoopEnd >>= 1;
    00621
    00622                         if (mFlags & XFCAUDIO_16BIT)
    00623                         {
    00624                             UINT32 a;
    00625                             for (a = 0; a < smp.mSize; ++a)
    00626                             {
    00627                                 ns = (INT16)(os + *(temp + a));
    00628                                 *((INT16 *)smp.mOffset + a) = ns;
    00629                                 os = ns;
    00630                             }
    00631                         }
    00632                         else
    00633                         {
    00634                             UINT32 a;
    00635                             for (a = 0; a < smp.mSize; ++a)
    00636                             {
    00637                                 ns = (INT16)(os + *(temp + a));
    00638                                 *((INT8 *)smp.mOffset + a) = (INT8)(ns >> 8);
    00639                                 os = ns;
    00640                             }
    00641
    00642                             smp.m16Bit = 0;
    00643
    00644                             INT8 *temp = new INT8[smp.mSize];
    00645                             memcpy(temp, smp.mOffset, smp.mSize);
    00646                             delete[] (INT8 *)smp.mOffset;
    00647                             smp.mOffset = temp;
    00648                         }
    00649                     }
    00650                     else
    00651                     {
    00652                         INT8 os, ns;
    00653                         os = 0;
    00654                         UINT32 a;
    00655                         for (a = 0; a < smp.mSize; a++)
    00656                         {
    00657                             ns = (INT8)(os + *((INT8 *)smp.mOffset + a));
    00658                             *((INT8 *)smp.mOffset + a) = ns;
    00659                             os = ns;
    00660                         }
    00661                     }
    00662                 }
    00663             }
    00664
    00665             ins.mVolumeFadeout = REALf(xmInstrument.mVolumeFadeout / 65536.0f);
    00666
    00667             if (xmInstrument.mVibratoRate)
    00668                 ins.mIsVibrato = 1;
    00669             else
    00670                 ins.mIsVibrato = 0;
    00671
    00672             ins.mVibratoType = xmInstrument.mVibratoType;
    00673             ins.mVibratoSweep = xmInstrument.mVibratoSweep;
    00674             ins.mVibratoDepth = xmInstrument.mVibratoDepth;
    00675             ins.mVibratoRate = xmInstrument.mVibratoRate;
    00676
    00677             debugPrint(aTextout, "sampleheader size: %d \n", xmInstrument.mSampleHeaderSize);
    00678
    00679             debugPrint(aTextout, "keyboard: ");
    00680
    00681             for (ii = 0; ii < 96; ii++)
    00682             {
    00683                 debugPrint(aTextout, "%d, ", xmInstrument.mKeyboard[ii]);
    00684                 if (((ii + 1) % 20) == 0)
    00685                     debugPrint(aTextout, "\n    ");
    00686             }
    00687
    00688             memcpy(ins.mKeyboard, xmInstrument.mKeyboard, 96);
    00689
    00690             debugPrint(aTextout, "\n");
    00691             debugPrint(aTextout, "volume. envelope: ");
    00692
    00693 //            if (xmInstrument.mVolEnvType & ENVELOPE_LOOP)
    00694 //                xmInstrument.mNbVolEnvPoints =
    00695 //                    xmInstrument.mVolEnvLoopEnd + 1;
    00696
    00697             for (ii = 0; ii < xmInstrument.mNbVolEnvPoints * 2; ii++)
    00698             {
    00699                 debugPrint(aTextout, "%d, ", xmInstrument.mVolumeEnvelope[ii]);
    00700
    00701                 if (((ii + 1) % 20) == 0)
    00702                     debugPrint(aTextout, "\n    ");
    00703             }
    00704
    00705             debugPrint(aTextout, "\n");
    00706             debugPrint(aTextout, "pan. envelope: ");
    00707
    00708 //            if (xmInstrument.mPanEnvType & ENVELOPE_LOOP)
    00709 //                xmInstrument.mNbPanEnvPoints =
    00710 //                    xmInstrument.mPanEnvLoopEnd + 1;
    00711
    00712             for (ii = 0; ii < xmInstrument.mNbPanEnvPoints * 2; ii++)
    00713             {
    00714                 debugPrint(aTextout, "%d, ", xmInstrument.mPanningEnvelope[ii]);
    00715
    00716                 if (((ii + 1) % 20) == 0)
    00717                     debugPrint(aTextout, "\n    ");
    00718             }
    00719
    00720             // Volume envelope
    00721             ins.mVolEnvType = xmInstrument.mVolEnvType;
    00722
    00723             if (xmInstrument.mVolEnvLoopStart != xmInstrument.mVolEnvLoopEnd)
    00724             {
    00725                 ins.mVolEnvLoopStart = xmInstrument.mVolumeEnvelope[
    00726                     xmInstrument.mVolEnvLoopStart * 2];
    00727                 ins.mVolEnvLoopEnd = xmInstrument.mVolumeEnvelope[
    00728                     xmInstrument.mVolEnvLoopEnd * 2];
    00729             }
    00730             memset(ins.mVolumeEnvelope, 0, XMFORMAT_SIZEOF_ENVELOPE);
    00731
    00732             if (xmInstrument.mNbVolEnvPoints == 1)
    00733             {
    00734                 // Volume envelope fix for trackers that don't follow FT2 standard
    00735                 ins.mVolumeEnvelope[0] = REALf(xmInstrument.mVolumeEnvelope[1] / 64.0f);
    00736             }
    00737             else
    00738             {
    00739                 for (ii = 0; ii < xmInstrument.mNbVolEnvPoints - 1; ii++)
    00740                 {
    00741                     x1 = xmInstrument.mVolumeEnvelope[(ii * 2)];
    00742                     y1 = xmInstrument.mVolumeEnvelope[(ii * 2) + 1];
    00743                     x2 = xmInstrument.mVolumeEnvelope[((ii + 1) * 2)];
    00744                     y2 = xmInstrument.mVolumeEnvelope[((ii + 1) * 2) + 1];
    00745
    00746                     dx = (y2 - y1) / (x2 - x1);
    00747
    00748                     for (xx = x1; xx <= x2; xx++)
    00749                     {
    00750                         ins.mVolumeEnvelope[xx] = REALf(y1 / 64.0f);
    00751                         y1 += dx;
    00752                     }
    00753                 }
    00754             }
    00755
    00756             if (xmInstrument.mVolEnvType & ENVELOPE_SUSTAIN)
    00757                 ins.mVolEnvSustain = xmInstrument.mVolumeEnvelope[
    00758                     xmInstrument.mVolEnvSustain * 2];
    00759
    00760             if (xmInstrument.mNbVolEnvPoints > 0)
    00761                 ins.mVolEnvEnd = xmInstrument.mVolumeEnvelope[
    00762                     (xmInstrument.mNbVolEnvPoints - 1) * 2];
    00763
    00764             // Panning envelope
    00765             ins.mPanEnvType = xmInstrument.mPanEnvType;
    00766
    00767             if (xmInstrument.mPanEnvLoopStart != xmInstrument.mPanEnvLoopEnd)
    00768             {
    00769                 ins.mPanEnvLoopStart = xmInstrument.mPanningEnvelope[
    00770                     xmInstrument.mPanEnvLoopStart * 2];
    00771                 ins.mPanEnvLoopEnd = xmInstrument.mPanningEnvelope[
    00772                     xmInstrument.mPanEnvLoopEnd * 2];
    00773             }
    00774             memset(ins.mPanningEnvelope, 0, XMFORMAT_SIZEOF_ENVELOPE);
    00775
    00776             if (xmInstrument.mNbPanEnvPoints == 1)
    00777             {
    00778                 // Panning envelope fix for trackers that don't follow FT2 standard
    00779                 ins.mPanningEnvelope[0] = (UINT8)xmInstrument.mPanningEnvelope[1];
    00780             }
    00781             else
    00782             {
    00783                 for (ii = 0; ii < xmInstrument.mNbPanEnvPoints - 1; ii++)
    00784                 {
    00785                     x1 = xmInstrument.mPanningEnvelope[(ii * 2)];
    00786                     y1 = xmInstrument.mPanningEnvelope[(ii * 2) + 1];
    00787                     x2 = xmInstrument.mPanningEnvelope[((ii + 1) * 2)];
    00788                     y2 = xmInstrument.mPanningEnvelope[((ii + 1) * 2) + 1];
    00789
    00790                     dx = (y2 - y1) / (x2 - x1);
    00791
    00792                     for (xx = x1; xx < x2; xx++)
    00793                     {
    00794                         ins.mPanningEnvelope[xx] = (UINT8)((INT8)y1);
    00795                         y1 += dx;
    00796                     }
    00797                 }
    00798             }
    00799
    00800             ins.mPanEnvSustain = xmInstrument.mPanningEnvelope[
    00801                 xmInstrument.mPanEnvSustain * 2];
    00802
    00803             if (xmInstrument.mNbPanEnvPoints > 0)
    00804                 ins.mPanEnvEnd = xmInstrument.mPanningEnvelope[
    00805                     (xmInstrument.mNbPanEnvPoints - 1) * 2];
    00806
    00807             debugPrint(aTextout, "\n");
    00808
    00809             debugPrint(aTextout, "nof volpoints %d\n",
    00810                        xmInstrument.mNbVolEnvPoints);
    00811             debugPrint(aTextout, "nof panpoints %d\n",
    00812                        xmInstrument.mNbPanEnvPoints);
    00813             debugPrint(aTextout, "volume. sustain %d\n",
    00814                        xmInstrument.mVolEnvSustain);
    00815             debugPrint(aTextout, "volume. loop start %d\n",
    00816                        xmInstrument.mVolEnvLoopStart);
    00817             debugPrint(aTextout, "volume. loop end %d\n",
    00818                        xmInstrument.mVolEnvLoopEnd);
    00819             debugPrint(aTextout, "pan. sustain %d\n",
    00820                        xmInstrument.mPanEnvSustain);
    00821             debugPrint(aTextout, "pan. loop start %d\n",
    00822                        xmInstrument.mPanEnvLoopStart);
    00823             debugPrint(aTextout, "pan. loop end %d\n",
    00824                        xmInstrument.mPanEnvLoopEnd);
    00825             debugPrint(aTextout, "volume. type %d\n", xmInstrument.mVolEnvType);
    00826             debugPrint(aTextout, "  env. on? %d\n",
    00827                        (xmInstrument.mVolEnvType & ENVELOPE_ON) ? 1 : 0);
    00828             debugPrint(aTextout, "  env. sustain? %d\n",
    00829                        (xmInstrument.mVolEnvType & ENVELOPE_SUSTAIN) ? 1 : 0);
    00830             debugPrint(aTextout, "  env. loop? %d \n",
    00831                        (xmInstrument.mVolEnvType & ENVELOPE_LOOP) ? 1 : 0);
    00832             debugPrint(aTextout, "pan. type %d\n",
    00833                        xmInstrument.mPanEnvType);
    00834
    00835             debugPrint(aTextout, "  env. on? %d\n",
    00836                        (xmInstrument.mPanEnvType & ENVELOPE_ON) ? 1 : 0);
    00837             debugPrint(aTextout, "  env. sustain? %d\n",
    00838                        (xmInstrument.mPanEnvType & ENVELOPE_SUSTAIN) ? 1 : 0);
    00839             debugPrint(aTextout, "  env. loop? %d \n",
    00840                        (xmInstrument.mPanEnvType & ENVELOPE_LOOP) ? 1 : 0);
    00841
    00842             debugPrint(aTextout, "vibr. type %d \n",
    00843                        xmInstrument.mVibratoType);
    00844             debugPrint(aTextout, "vibr. sweep %d \n",
    00845                        xmInstrument.mVibratoSweep);
    00846             debugPrint(aTextout, "vibr. depth %d \n",
    00847                        xmInstrument.mVibratoDepth);
    00848             debugPrint(aTextout, "vibr. rate %d \n",
    00849                        xmInstrument.mVibratoRate);
    00850             debugPrint(aTextout, "volume. fadeout %d \n\n",
    00851                        xmInstrument.mVolumeFadeout);
    00852         }
    00853         else
    00854         {
    00855             f->seek(skip, SEEK_CUR);
    00856         }
    00857
    00858         debugPrint(aTextout, "-----\n\n");
    00859     }
    00860
    00861     mSong.mNbInstruments = mXMHeader.mNbInstruments;
    00862
    00863     debugPrint(aTextout, "XM read. \n");
    00864     debugPrint(aTextout, "Not changing pattern structure yet.. \n");
    00865
    00866     f->close();
    00867
    00868     return 0;
    00869 }
    00870
    00871
    00872 UINT32 XFuXMPlayer::getPeriod(INT8 aNote, INT8 aFinetune)
    00873 {
    00874     if (aNote < 0) aNote = 0;
    00875     if (aNote > 96) aNote = 96;
    00876
    00877     return (7680 - (aNote << 6) - (aFinetune >> 1));
    00878 }
    00879
    00880
    00881 UINT32 XFuXMPlayer::getSpeed(UINT32 aPeriod, FLOAT32 aSamplingRate)
    00882 {
    00883     INT32 freq;
    00884     INT32 shift = (INT32)(aPeriod / 768);
    00885
    00886     if (shift >= 0)
    00887         freq = linearFrequencyTable[aPeriod - (shift << 9) - (shift << 8)] >> shift;
    00888     //return linearFrequencyTable[aPeriod % 768] >> shift;
    00889     else
    00890         freq = linearFrequencyTable[aPeriod - (shift << 9) - (shift << 8)] << (-shift);
    00891     //return linearFrequencyTable[aPeriod % 768] << (-shift);
    00892
    00893 /*
    00894     FLOAT32 freq = (FLOAT32)(8363.0f * pow(2.0f, (4608.f - (FLOAT32)period) / 768.0f));
    00895 */
    00896
    00897     return (INT32)((freq / aSamplingRate) * FP_VALUE);
    00898 }
    00899
    00900
    00901 XFuXMFormatAtom XFuXMPlayer::getAtom()
    00902 {
    00903     UINT8 *XMFORMAT_pa = mPatternData[mPatternNb].mData;
    00904     XFuXMFormatAtom ta;
    00905     UINT8 b;
    00906     ta.mNote = 0;
    00907     ta.mVolume = 0;
    00908     ta.mInstrumentNb = 0;
    00909     ta.mEffectType = 0;
    00910     ta.mEffectValue = 0;
    00911
    00912     b = *(XMFORMAT_pa + mPpoint++);
    00913     if (b & 0x80)
    00914     {
    00915         // Packed atom
    00916         if (b & 0x1)
    00917             ta.mNote = *(XMFORMAT_pa + mPpoint++);
    00918         if (b & 0x2)
    00919             ta.mInstrumentNb = *(XMFORMAT_pa + mPpoint++);
    00920         if (b & 0x4)
    00921             ta.mVolume = *(XMFORMAT_pa + mPpoint++);
    00922         if (b & 0x8)
    00923             ta.mEffectType = *(XMFORMAT_pa + mPpoint++);
    00924         if (b & 0x10)
    00925             ta.mEffectValue = *(XMFORMAT_pa + mPpoint++);
    00926     }
    00927     else
    00928     {
    00929         // Normal atom
    00930         ta.mNote = b;
    00931         ta.mInstrumentNb = *(XMFORMAT_pa + mPpoint++);
    00932         ta.mVolume = *(XMFORMAT_pa + mPpoint++);
    00933         ta.mEffectType = *(XMFORMAT_pa + mPpoint++);
    00934         ta.mEffectValue = *(XMFORMAT_pa + mPpoint++);
    00935     }
    00936
    00937     return ta;
    00938 }
    00939
    00940
    00941 void XFuXMPlayer::initChannel(XFuXMChannel &aCh)
    00942 {
    00943     aCh.mIsValid = 1;
    00944     aCh.mInitSample = 0;
    00945
    00946     // Initialize sample if valid note
    00947     if ((aCh.mTa.mNote > 0) && (aCh.mTa.mNote < 97))
    00948     {
    00949         aCh.mNote = (INT8)(aCh.mTa.mNote - 1);
    00950         aCh.mInitSample = 1;
    00951
    00952         aCh.mTremorTicker = 0;
    00953         aCh.mMultiRetrigTicker = 0;
    00954     }
    00955     else if (aCh.mTa.mNote != 0)
    00956         aCh.mIsValid = 0;
    00957
    00958     aCh.mVolumeColumn = aCh.mTa.mVolume;
    00959
    00960     if (aCh.mTa.mInstrumentNb != 0)
    00961     {
    00962         // New instrument
    00963         aCh.mInstrumentNb = (INT16)(aCh.mTa.mInstrumentNb - 1);
    00964
    00965         if (aCh.mInstrumentNb < mSong.mNbInstruments)
    00966         {
    00967             aCh.mCurrentInstrument = mInstruments[aCh.mInstrumentNb];
    00968
    00969             if (aCh.mCurrentInstrument.mKeyboard[aCh.mNote] < aCh.mCurrentInstrument.mNbSamples)
    00970             {
    00971                 if (aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]].mOffset != NULL)
    00972                 {
    00973                     aCh.mCurrentSample = aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]];
    00974                 }
    00975                 else aCh.mIsValid = 0;
    00976             }
    00977             else aCh.mIsValid = 0;
    00978         }
    00979         else aCh.mIsValid = 0;
    00980
    00981         aCh.mVolume = aCh.mCurrentSample.mVolume;
    00982         aCh.mBaseVolume = aCh.mVolume;
    00983
    00984         aCh.mPan = aCh.mCurrentSample.mPan;
    00985     }
    00986     else
    00987     {
    00988         if ((aCh.mInstrumentNb != -1) && (aCh.mInstrumentNb < mSong.mNbInstruments))
    00989         {
    00990             aCh.mCurrentInstrument = mInstruments[aCh.mInstrumentNb];
    00991
    00992             if (aCh.mCurrentInstrument.mKeyboard[aCh.mNote] < aCh.mCurrentInstrument.mNbSamples)
    00993             {
    00994                 if (aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]].mOffset != NULL)
    00995                 {
    00996                     aCh.mCurrentSample = aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]];
    00997                 }
    00998                 else aCh.mIsValid = 0;
    00999             }
    01000             else aCh.mIsValid = 0;
    01001         }
    01002         else aCh.mIsValid = 0;
    01003     }
    01004
    01005     aCh.mOldPeriod = aCh.mPeriod;
    01006
    01007     // Do not initialize sound if note delay or pattern delay effect on
    01008     if ((aCh.mInitSample) || (mPatternDelayCounter != 0))
    01009         initSound(aCh);
    01010 }
    01011
    01012
    01013 void XFuXMPlayer::initSound(XFuXMChannel &aCh)
    01014 {
    01015     if (aCh.mIsValid)
    01016     {
    01017         // Initialize sample
    01018         if (aCh.mInitSample) aCh.mIsSample = 1;
    01019
    01020         // New note
    01021         aCh.mDirection = 1;
    01022
    01023         // Init vibrato
    01024         /* Instrument vibrato is independent
    01025         aCh.mIsVibrato = aCh.mCurrentInstrument.mIsVibrato;
    01026         if (aCh.mCurrentInstrument.mVibratoDepth != 0)
    01027             aCh.mVibratoDepth = aCh.mCurrentInstrument.mVibratoDepth;
    01028         if (aCh.mCurrentInstrument.mVibratoRate != 0)
    01029             aCh.mVibratoRate = aCh.mCurrentInstrument.mVibratoRate;
    01030         */
    01031         aCh.mIsVibrato = 0;
    01032
    01033         if ((aCh.mVibratoWaveform & WAVEFORM_NO_RETRIG) == 0) aCh.mVibratoPointer = 0;
    01034         if ((aCh.mTremoloWaveform & WAVEFORM_NO_RETRIG) == 0) aCh.mTremoloPointer = 0;
    01035
    01036         // Init volume envelope
    01037         aCh.mVolEnvType = aCh.mCurrentInstrument.mVolEnvType;
    01038         aCh.mVolEnvPointer = 0;
    01039         aCh.mVolEnvSpeed = 1;
    01040         aCh.mVolEnvLoopStart = aCh.mCurrentInstrument.mVolEnvLoopStart;
    01041         aCh.mVolEnvLoopEnd = aCh.mCurrentInstrument.mVolEnvLoopEnd;
    01042         aCh.mVolEnvSustain = aCh.mCurrentInstrument.mVolEnvSustain;
    01043
    01044         aCh.mVolumeFadeout = aCh.mCurrentInstrument.mVolumeFadeout;
    01045         aCh.mVolumeFadeoutValue = REAL(1);
    01046
    01047         // Init panning envelope
    01048         aCh.mPanEnvType = aCh.mCurrentInstrument.mPanEnvType;
    01049         aCh.mPanEnvPointer = 0;
    01050         aCh.mPanEnvSpeed = 1;
    01051         aCh.mPanEnvLoopStart = aCh.mCurrentInstrument.mPanEnvLoopStart;
    01052         aCh.mPanEnvLoopEnd = aCh.mCurrentInstrument.mPanEnvLoopEnd;
    01053         aCh.mPanEnvSustain = aCh.mCurrentInstrument.mPanEnvSustain;
    01054
    01055         aCh.mSustainReleased = 0;
    01056
    01057         aCh.mOffset = aCh.mCurrentSample.mOffset;
    01058         aCh.mFinetune = aCh.mCurrentSample.mFinetune;
    01059
    01060         if ((aCh.mEffectType != 0x3) &&   // No tone portamento
    01061             (aCh.mEffectType != 0x5) &&   // No tone portamento + volume slide
    01062             (aCh.mVolumeColumn < 0xF0)) // No volume column tone portamento
    01063             aCh.mPointer = 0; // Reset pointer if no tone effect
    01064
    01065         aCh.mLength = (aCh.mCurrentSample.mSize << FP_BITS);
    01066         aCh.mPeriod = getPeriod((INT8)(aCh.mNote + aCh.mCurrentSample.mRelativeNote), aCh.mFinetune);
    01067         aCh.mBasePeriod = aCh.mPeriod;
    01068
    01069         aCh.mLoop = 0;
    01070         if (aCh.mCurrentSample.mLoopForward) aCh.mLoop = LOOP_FORWARD;
    01071         if (aCh.mCurrentSample.mLoopPingpong) aCh.mLoop = LOOP_PINGPONG;
    01072         aCh.mLoopStart = (aCh.mCurrentSample.mLoopStart << FP_BITS);
    01073         aCh.mLoopEnd = (aCh.mCurrentSample.mLoopEnd << FP_BITS);
    01074     }
    01075     else
    01076         aCh.mIsSample = 0;
    01077 }
    01078
    01079
    01080 void XFuXMPlayer::notifyHandlers(XFuXMChannel &aCh)
    01081 {
    01082     XFuXMPlayerEvent event;
    01083
    01084     event.mNote = aCh.mNote;
    01085     event.mInstrumentNb = aCh.mInstrumentNb;
    01086     event.mVolume = aCh.mVolume;
    01087
    01088     if ((aCh.mEffectType != 0xE) && (aCh.mEffectType != 0x21))
    01089     {
    01090         event.mEffectType = aCh.mEffectType;
    01091         event.mEffectValue = aCh.mEffectValue;
    01092     }
    01093     else
    01094     {
    01095         event.mEffectType = (INT16)((aCh.mEffectType << 4) | (aCh.mEffectValue >> 4));
    01096         event.mEffectValue = (INT16)(aCh.mEffectValue & 0xF);
    01097     }
    01098
    01099     event.mPlayer = this;
    01100
    01101     XFcLinkedList<XFuXMPlayerEventHandlerSlot>::forwardIterator i;
    01102     XFuXMPlayerEventHandlerSlot temp;
    01103
    01104     for (i = mEventHandlers->forwardBegin(); i != mEventHandlers->forwardEnd(); ++i)
    01105     {
    01106         temp = i.getData();
    01107
    01108         if (((temp.mEvent.mNote != -1) && (temp.mEvent.mNote == event.mNote)) ||
    01109             ((temp.mEvent.mInstrumentNb != -1) && (temp.mEvent.mInstrumentNb == event.mInstrumentNb)) ||
    01110             ((temp.mEvent.mEffectType != -1) && (temp.mEvent.mEffectType == event.mEffectType)))
    01111         {
    01112             temp.mHandler->handleXMPlayerEvent(event);
    01113         }
    01114     }
    01115 }
    01116
    01117
    01118 void XFuXMPlayer::initSong(INT16 aStartOrder)
    01119 {
    01120     INT i;
    01121
    01122     if ((aStartOrder < 0) || (aStartOrder >= mSong.mSongLength)) aStartOrder = 0;
    01123     mCurrentOrder = (INT16)(aStartOrder - 1);
    01124
    01125     mPatternNb = mSong.mOrderTable[aStartOrder];
    01126     if (mPatternNb >= mSong.mNbPatterns) mPatternNb = mSong.mOrderTable[0];
    01127
    01128     mCurrentRow = 1024;
    01129
    01130     mPatternDelayCounter = 0;
    01131     mPatternDelayCounterTemp = 0;
    01132     mPatternDelaySkip = 0;
    01133     mJumpFlag = 0;
    01134     mIsRead = 1;
    01135
    01136     mTickRate = (2.0f * mSong.mBpm / 5.0f);
    01137
    01138     mSamplesPerTick = (INT32)(mSamplingRate / mTickRate);
    01139
    01140     mCurrentTick = (UINT8)(mSong.mTempo - 1); // Playing starts from last tick
    01141     mSamplePointer = mSamplesPerTick;         // Playing starts from last sample of last tick
    01142
    01143     mTotalTicks = 0;
    01144
    01145     mSong.mGlobalVolume = 64;
    01146
    01147     for (i = 0; i < mSong.mNbChannels; i++)
    01148     {
    01149         XFuXMChannel &ch = mChannels[i];
    01150
    01151         ch.mOffset = NULL;
    01152         ch.mPointer = 0;
    01153         ch.mLength = 0;
    01154         ch.mInstrumentNb = -1;
    01155         ch.mSpeed = 0;
    01156         ch.mPeriod = 0;
    01157
    01158         ch.mLoop = 0;
    01159         ch.mLoopStart = 0;
    01160         ch.mLoopEnd = 0;
    01161
    01162         ch.mIsSample = 0;
    01163
    01164         ch.mVolume = 0;
    01165         ch.mBaseVolume = 0;
    01166         ch.mFinalOldVolume = 0;
    01167         ch.mFinalVolumeSpeed = 0;
    01168
    01169         ch.mNote = 0;
    01170
    01171         ch.mDirection = 1;
    01172
    01173         ch.mVolEnvType = 0;
    01174         ch.mVolEnvPointer = 0;
    01175         ch.mVolEnvSpeed = 0;
    01176         ch.mVolEnvLoopStart = 0;
    01177         ch.mVolEnvLoopEnd = 0;
    01178         ch.mVolEnvSustain = 0;
    01179         ch.mVolEnvValue = 0;
    01180
    01181         ch.mPanEnvType = 0;
    01182         ch.mPanEnvPointer = 0;
    01183         ch.mPanEnvSpeed = 0;
    01184         ch.mPanEnvLoopStart = 0;
    01185         ch.mPanEnvLoopEnd = 0;
    01186         ch.mPanEnvSustain = 0;
    01187         ch.mPanEnvValue = 0;
    01188
    01189         ch.mVolumeFadeout = 0;
    01190         ch.mVolumeFadeoutValue = 0;
    01191
    01192         ch.mSustainReleased = 0;
    01193
    01194         ch.mVolumeColumn = 0;
    01195
    01196         ch.mEffectType = 0;
    01197         ch.mEffectValue = 0;
    01198         ch.mTonePortamentoV = 0;
    01199         ch.mVolumeSlideV = 0;
    01200         ch.mGlobalVolumeSlideV = 0;
    01201         ch.mFineVolumeSlideUpV = 0;
    01202         ch.mFineVolumeSlideDownV = 0;
    01203         ch.mFinePortamentoUpV = 0;
    01204         ch.mFinePortamentoDownV = 0;
    01205         ch.mFineVolumeSlideUpV = 0;
    01206         ch.mFineVolumeSlideDownV = 0;
    01207         ch.mGlobalVolumeSlideV = 0;
    01208         ch.mMultiRetrigVolumeV = 0;
    01209         ch.mMultiRetrigRateV = 0;
    01210         ch.mTremorV = 0;
    01211         ch.mExtraFinePortamentoUpV = 0;
    01212         ch.mExtraFinePortamentoDownV = 0;
    01213
    01214         ch.mMultiRetrigTicker = 0;
    01215         ch.mTremorTicker = 0;
    01216
    01217         ch.mPeriod = 0;
    01218         ch.mBasePeriod = 0;
    01219         ch.mOldPeriod = 0;
    01220         ch.mDestPeriod = 0;
    01221
    01222         ch.mIsVibrato = 0;
    01223         ch.mVibratoDepth = 0;
    01224         ch.mVibratoRate = 0;
    01225         ch.mVibratoPointer = 0;
    01226         ch.mVibratoWaveform = WAVEFORM_SINEWAVE;
    01227
    01228         ch.mTremoloDepth = 0;
    01229         ch.mTremoloRate = 0;
    01230         ch.mTremoloPointer = 0;
    01231         ch.mTremoloWaveform = WAVEFORM_SINEWAVE;
    01232     }
    01233 }
    01234
    01235
    01236 INT32 XFuXMPlayer::getTick()
    01237 {
    01238     return (INT32)((mTotalTicks * 1000) / mSamplingRate);
    01239 }
    01240
    01241
    01242 INT16 XFuXMPlayer::getCurrentOrder()
    01243 {
    01244     return mCurrentOrder;
    01245 }
    01246
    01247
    01248 void XFuXMPlayer::addHandler(XFuXMPlayerEvent aEvent, XFuXMPlayerEventHandler *aHandler)
    01249 {
    01250     if (aHandler != NULL)
    01251     {
    01252         XFuXMPlayerEventHandlerSlot temp;
    01253         temp.mEvent = aEvent;
    01254         temp.mHandler = aHandler;
    01255
    01256         mEventHandlers->addLast(temp);
    01257     }
    01258 }
    01259
    01260
    01261 INT XFuXMPlayer::removeHandler(XFuXMPlayerEventHandler *aHandler)
    01262 {
    01263     if (aHandler != NULL)
    01264     {
    01265         XFuXMPlayerEventHandlerSlot temp;
    01266         temp.mHandler = aHandler;
    01267
    01268         return mEventHandlers->remove(temp);
    01269     }
    01270
    01271     return 0;
    01272 }
    01273
    01274
    01275 void XFuXMPlayer::removeHandlers()
    01276 {
    01277     XFcLinkedList<XFuXMPlayerEventHandlerSlot>::forwardIterator i = mEventHandlers->forwardBegin();
    01278     XFuXMPlayerEventHandlerSlot temp;
    01279
    01280     while (i.isValid())
    01281     {
    01282         mEventHandlers->remove(i);
    01283     }
    01284 }
    01285
    01286
    01287 void XFuXMPlayer::stop()
    01288 {
    01289     initSong(0);
    01290 }
    01291
    01292 // For MSVC
    01293 #pragma warning(disable:4244)
    01294
    01295 UINT32 XFuXMPlayer::stream(void *aBuffer, INT32 aTargetSamples, INT32 aOffset,
    01296                            INT32 aSamples)
    01297 {
    01298     INT32 cLeft, cRight;
    01299
    01300     INT32 chan;
    01301
    01302     INT32 index;
    01303     INT32 targetOffset = aOffset;
    01304     INT32 counter;
    01305     INT32 indicesLeft;
    01306     INT32 ticksLeft;
    01307     INT32 samplesToRender;
    01308
    01309     INT32 delta;
    01310     INT32 val1, val2;
    01311     INT32 value;
    01312     INT32 temp;
    01313
    01314     XFuXMFormatAtom ta;
    01315     INT16 *vibratoTable = mSineWaveTable;
    01316     INT16 *tremoloTable = mSineWaveTable;
    01317
    01318     for (index = 0; index < aSamples; )
    01319     {
    01320         if (mSamplePointer == mSamplesPerTick)
    01321         {
    01322             // Tick finished
    01323             mSamplePointer = 0;
    01324
    01325             mRamp = 0;
    01326
    01327             if (mIsRead && (++mCurrentTick == mSong.mTempo))
    01328             {
    01329                 // Row finished
    01330                 mCurrentTick = 0;
    01331
    01332                 if (mPatternDelayCounter == 0)
    01333                 {
    01334                     mCurrentRow++;
    01335                     mPatternDelaySkip = 0;
    01336                 }
    01337                 else
    01338                     mPatternDelayCounter--;
    01339
    01340                 if ((mCurrentRow >= mXMPatternHeaders[mPatternNb].mNbRows) || (mJumpFlag != 0))
    01341                 {
    01342                     // Pattern finished
    01343                     mCurrentOrder++;
    01344                     if (mCurrentOrder >= mSong.mSongLength) mCurrentOrder = mSong.mRestartPosition;
    01345
    01346                     mPatternNb = mSong.mOrderTable[mCurrentOrder];
    01347                     if (mPatternNb >= mSong.mNbPatterns) mPatternNb = mSong.mOrderTable[0];
    01348
    01349                     if (mJumpFlag == 0) mCurrentRow = 0;
    01350
    01351                     mJumpFlag = 0;
    01352                 }
    01353
    01354                 mPpoint = mPatternData[mPatternNb].mRows[mCurrentRow];
    01355
    01356                 for (chan = 0; chan < mSong.mNbChannels; chan++)
    01357                 {
    01358                     XFuXMChannel &ch = mChannels[chan];
    01359
    01360                     if (mPatternDelayCounter == 0)
    01361                     {
    01362                         ta = getAtom(); // Get track data
    01363
    01364                         ch.mTa = ta;
    01365
    01366                         ch.mEffectType = ta.mEffectType;
    01367                         ch.mEffectValue = ta.mEffectValue;
    01368
    01369                         if (!((ch.mEffectType == 0xE) &&
    01370                             // No change if note delay effect
    01371                             (((ch.mEffectValue >> 4) & 0xF) == 0xD)))
    01372                         {
    01373                             initChannel(ch);
    01374                         }
    01375                     }
    01376
    01377                     // Volume column effects
    01378                     if (ch.mVolumeColumn != 0)
    01379                     {
    01380                         // Set volume
    01381                         if ((ch.mVolumeColumn >= 0x10) && (ch.mVolumeColumn <= 0x50))
    01382                         {
    01383                             ch.mVolume = (INT8)(ch.mVolumeColumn - 0x10);
    01384                             if (ch.mVolume > 0x40) ch.mVolume = 0x40;
    01385                             ch.mBaseVolume = ch.mVolume;
    01386                         }
    01387                         else
    01388                         {
    01389                             switch (ch.mVolumeColumn >> 4)
    01390                             {
    01391                             case 0x8:   // Fine volume slide down (arrow down)
    01392                                 if (ch.mVolume > 0) ch.mVolume -= (ch.mVolumeColumn & 0xF);
    01393                                 ch.mBaseVolume = ch.mVolume;
    01394                                 break;
    01395
    01396                             case 0x9:    // Fine volume slide up (arrow up)
    01397                                 if (ch.mVolume < 0x40) ch.mVolume += (ch.mVolumeColumn & 0xF);
    01398                                 ch.mBaseVolume = ch.mVolume;
    01399                                 break;
    01400
    01401                             case 0xA:   // Set vibrato speed (Sxy)
    01402                                 if ((ch.mVolumeColumn & 0xF) != 0)
    01403                                     ch.mVibratoRate = (UINT8)(ch.mVolumeColumn & 0xF);
    01404                                 break;
    01405
    01406                             case 0xB:   // Set vibrato depth (Vxy)
    01407                                 if ((ch.mVolumeColumn & 0xF) != 0)
    01408                                 {
    01409                                     ch.mVibratoDepth = (UINT8)((ch.mVolumeColumn & 0xF) * 4);
    01410                                     ch.mIsVibrato = 1;
    01411                                 }
    01412                                 break;
    01413
    01414                             case 0xC:   // Set panning (Pxy)
    01415                                 ch.mPan = (UINT8)((ch.mVolumeColumn & 0xF) << 4);
    01416                                 break;
    01417
    01418                             case 0xD:   // Panning slide left (left arrow)
    01419                                 if (ch.mPan > 0) ch.mPan -= (ch.mVolumeColumn & 0xF);
    01420                                 break;
    01421
    01422                             case 0xE:   // Panning slide right (right arrow)
    01423                                 if (ch.mPan < 0xFF) ch.mPan += (ch.mVolumeColumn & 0xF);
    01424                                 break;
    01425
    01426                             case 0xF:   // Tone portamento (Mxy)
    01427                                 if ((ch.mVolumeColumn & 0xF) != 0)
    01428                                     ch.mTonePortamentoV = (UINT8)((ch.mVolumeColumn & 0xF) << 4);
    01429
    01430                                 if ((ch.mTa.mNote != 0) && (ch.mTa.mNote != 97))
    01431                                 {
    01432                                     ch.mDestPeriod = ch.mPeriod;
    01433                                     ch.mPeriod = ch.mOldPeriod;
    01434                                     ch.mBasePeriod = ch.mPeriod;
    01435                                 }
    01436                                 break;
    01437                             }
    01438                         }
    01439                     }
    01440
    01441                     // Row effects
    01442                     switch (ch.mEffectType)
    01443                     {
    01444                         case 0x0:   // Arpeggio (0xy)
    01445                             ch.mPeriod = ch.mBasePeriod;
    01446                             break;
    01447
    01448                         case 0x1:   // Portamento up (1xy)
    01449                             if (ch.mEffectValue != 0) ch.mPortamentoUpV = ch.mEffectValue;
    01450                             break;
    01451
    01452                         case 0x2:   // Portamento down (2xy)
    01453                             if (ch.mEffectValue != 0) ch.mPortamentoDownV = ch.mEffectValue;
    01454                             break;
    01455
    01456                         case 0x3:   // Tone portamento (3xy)
    01457                             if (ch.mOldPeriod != 0)
    01458                             {
    01459                                 if (ch.mEffectValue != 0) ch.mTonePortamentoV = ch.mEffectValue;
    01460
    01461                                 if ((ch.mTa.mNote != 0) && (ch.mTa.mNote != 97))
    01462                                 {
    01463                                     ch.mDestPeriod = ch.mPeriod;
    01464                                     ch.mPeriod = ch.mOldPeriod;
    01465                                     ch.mBasePeriod = ch.mPeriod;
    01466                                 }
    01467                             }
    01468                             break;
    01469
    01470                         case 0x4:   // Vibrato (4xy)
    01471                             if ((ch.mEffectValue & 0xF) != 0)
    01472                                 ch.mVibratoDepth = (UINT8)((ch.mEffectValue & 0xF) * 4);
    01473
    01474                             if ((ch.mEffectValue >> 4) != 0)
    01475                                 ch.mVibratoRate = (UINT8)(ch.mEffectValue >> 4);
    01476
    01477                             ch.mIsVibrato = 1;
    01478                             break;
    01479
    01480                         case 0x5:   // Tone portamento + volume slide (5xy)
    01481                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
    01482                             break;
    01483
    01484                         case 0x6:   // Vibrato + volume slide (6xy)
    01485                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
    01486
    01487                             ch.mIsVibrato = 1;
    01488                             break;
    01489
    01490                         case 0x7:   // Tremolo (7xy)
    01491                             if ((ch.mEffectValue & 0xF) != 0)
    01492                                 ch.mTremoloDepth = (UINT8)(ch.mEffectValue & 0xF);
    01493
    01494                             if ((ch.mEffectValue >> 4) != 0)
    01495                                 ch.mTremoloRate = (UINT8)(ch.mEffectValue >> 4);
    01496                             break;
    01497
    01498                         case 0x8:   // Set panning (8xy)
    01499                             ch.mPan = ch.mEffectValue;
    01500                             break;
    01501
    01502                         case 0x9:   // Sample offset (9xy)
    01503                             ch.mPointer = ch.mEffectValue << (8 + FP_BITS);
    01504                             XFCASSERT(ch.mPointer < ch.mLength);
    01505                             // FastTracker2 behaviour when not in debug mode,
    01506                             // if offset is beyond sample length, stop sample
    01507                             if (ch.mPointer >= ch.mLength) ch.mIsSample = 0;
    01508                             break;
    01509
    01510                         case 0xA:   // Volume slide (Axy)
    01511                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
    01512                             break;
    01513
    01514                         case 0xB:   // Jump to pattern (Bxy)
    01515                             if (mJumpFlag == 0)
    01516                             {
    01517                                 mCurrentRow = -1;
    01518                                 mCurrentOrder = (INT16)(ch.mEffectValue - 1);
    01519                                 mJumpFlag = 1;
    01520                             }
    01521                             break;
    01522
    01523                         case 0xC:   // Volume (Cxy)
    01524                             ch.mVolume = ch.mEffectValue;
    01525                             if (ch.mVolume > 0x40) ch.mVolume = 0x40;
    01526                             ch.mBaseVolume = ch.mVolume;
    01527                             break;
    01528
    01529                         case 0xD:   // Pattern break (Dxy)
    01530                             if (mJumpFlag == 0)
    01531                             {
    01532                                 mCurrentRow = (INT16)(ch.mEffectValue - 1);
    01533                                 mJumpFlag = 1;
    01534                             }
    01535                             break;
    01536
    01537                         case 0xE:   // Extra effects (Exy)
    01538                             switch ((ch.mEffectValue >> 4))
    01539                             {
    01540                                 case 0x1:   // Fine portamento up (E1y)
    01541                                     if ((ch.mEffectValue & 0xF) != 0)
    01542                                         ch.mFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
    01543
    01544                                     ch.mPeriod -= ch.mFinePortamentoUpV * 4;
    01545                                     ch.mBasePeriod = ch.mPeriod;
    01546                                     break;
    01547
    01548                                 case 0x2:   // Fine portamento down (E2y)
    01549                                     if ((ch.mEffectValue & 0xF) != 0)
    01550                                         ch.mFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
    01551
    01552                                     ch.mPeriod += ch.mFinePortamentoUpV * 4;
    01553                                     ch.mBasePeriod = ch.mPeriod;
    01554                                     break;
    01555
    01556                                 case 0x3:   // Glissando control (E3y), FIX ME!
    01557                                     break;
    01558
    01559                                 case 0x4:   // Vibrato waveform (E4y)
    01560                                     if ((ch.mEffectValue & 0xF) < 7)
    01561                                         ch.mVibratoWaveform = (UINT8)(ch.mEffectValue & 0xF);
    01562                                     break;
    01563
    01564                                 case 0x5:   // Set finetune (E5y)
    01565                                     ch.mFinetune = (INT8)((ch.mEffectValue & 0xF) << 1);
    01566                                     break;
    01567
    01568                                 case 0x6:   // Pattern loop (E6y), FIX ME!
    01569                                     break;
    01570
    01571                                 case 0x7:   // Tremolo waveform (E7y)
    01572                                     if ((ch.mEffectValue & 0xF) < 7)
    01573                                         ch.mTremoloWaveform = (UINT8)(ch.mEffectValue & 0xF);
    01574                                     break;
    01575
    01576                                 case 0xA:   // Fine volume slide up (EAy)
    01577                                     if ((ch.mEffectValue & 0xF) != 0)
    01578                                         ch.mFineVolumeSlideUpV = (UINT8)(ch.mEffectValue & 0xF);
    01579
    01580                                     if (ch.mVolume < 0x40) ch.mVolume += ch.mFineVolumeSlideUpV;
    01581                                     ch.mBaseVolume = ch.mVolume;
    01582                                     break;
    01583
    01584                                 case 0xB:   // Fine volume slide down (EBy)
    01585                                     if ((ch.mEffectValue & 0xF) != 0)
    01586                                         ch.mFineVolumeSlideDownV = (UINT8)(ch.mEffectValue & 0xF);
    01587
    01588                                     if (ch.mVolume > 0) ch.mVolume -= ch.mFineVolumeSlideDownV;
    01589                                     ch.mBaseVolume = ch.mVolume;
    01590                                     break;
    01591
    01592                                 case 0xE:   // Pattern delay (EEy)
    01593                                     if ((mPatternDelayCounter == 0) && (mPatternDelaySkip == 0))
    01594                                         mPatternDelayCounterTemp = (UINT8)(ch.mEffectValue & 0xF);
    01595                                     break;
    01596
    01597                                 }
    01598                             break;
    01599
    01600                         case 0xF:   // Tempo or BPM change (Fxy)
    01601                             if (ch.mEffectValue < 32)
    01602                             {
    01603                                 mSong.mTempo = ch.mEffectValue;
    01604                                 if (mSong.mTempo == 0) mIsRead = 0;
    01605                             }
    01606                             else
    01607                             { // BPM
    01608                                 mSong.mBpm = ch.mEffectValue;
    01609                                 mTickRate = 2.0f * mSong.mBpm / 5.0f;
    01610
    01611                                 mSamplesPerTick = (INT)(mSamplingRate / mTickRate);
    01612                             }
    01613                             break;
    01614
    01615                         case 0x10:  // Global volume (Gxy)
    01616                             mSong.mGlobalVolume = ch.mEffectValue;
    01617
    01618                             if (mSong.mGlobalVolume > 0x40) mSong.mGlobalVolume = 0x40;
    01619                             break;
    01620
    01621                         case 0x11:  // Global volume slide (Hxy)
    01622                             if (ch.mEffectValue != 0) ch.mGlobalVolumeSlideV = ch.mEffectValue;
    01623
    01624                             if (mSong.mGlobalVolume < 0x40)
    01625                                 mSong.mGlobalVolume += (ch.mGlobalVolumeSlideV >> 4) << 1;
    01626                             if (mSong.mGlobalVolume > 0)
    01627                                 mSong.mGlobalVolume -= (ch.mGlobalVolumeSlideV & 0xF) << 1;
    01628                             break;
    01629
    01630                         case 0x15:  // Set envelope position (Lxy)
    01631                             ch.mVolEnvPointer = ch.mPanEnvPointer = ch.mEffectValue;
    01632                             break;
    01633
    01634                         case 0x19:  // Panning slide (Pxy)
    01635                             if (ch.mEffectValue != 0) ch.mPanningSlideV = ch.mEffectValue;
    01636                             break;
    01637
    01638                         case 0x1B:  // Multi retrig note (Rxy)
    01639                             if ((ch.mEffectValue >> 4) != 0)
    01640                                 ch.mMultiRetrigVolumeV = (UINT8)(ch.mEffectValue >> 4);
    01641
    01642                             if ((ch.mEffectValue & 0xF) != 0)
    01643                                 ch.mMultiRetrigRateV = (UINT8)(ch.mEffectValue & 0xF);
    01644
    01645                             if (ch.mMultiRetrigRateV != 0)
    01646                             {
    01647                                 if ((ch.mMultiRetrigTicker % ch.mMultiRetrigRateV) == 0)
    01648                                 {
    01649                                     ch.mInitSample = 1;
    01650                                     initSound(ch);
    01651
    01652                                     if ((ch.mMultiRetrigVolumeV != 8) && (ch.mMultiRetrigTicker != 0))
    01653                                     {
    01654                                         // Don't affect volume on first tick
    01655                                         switch (ch.mMultiRetrigVolumeV)
    01656                                         {
    01657                                             case 0x1:
    01658                                                 ch.mVolume -= 1;
    01659                                                 break;
    01660                                             case 0x2:
    01661                                                 ch.mVolume -= 2;
    01662                                                 break;
    01663                                             case 0x3:
    01664                                                 ch.mVolume -= 4;
    01665                                                 break;
    01666                                             case 0x4:
    01667                                                 ch.mVolume -= 8;
    01668                                                 break;
    01669                                             case 0x5:
    01670                                                 ch.mVolume -= 16;
    01671                                                 break;
    01672                                             case 0x6:
    01673                                                 ch.mVolume = (INT8)((ch.mVolume * 2) / 3);
    01674                                                 break;
    01675                                             case 0x7:
    01676                                                 ch.mVolume >>= 1;
    01677                                                 break;
    01678                                             case 0x9:
    01679                                                 ch.mVolume += 1;
    01680                                                 break;
    01681                                             case 0xA:
    01682                                                 ch.mVolume += 2;
    01683                                                 break;
    01684                                             case 0xB:
    01685                                                 ch.mVolume += 4;
    01686                                                 break;
    01687                                             case 0xC:
    01688                                                 ch.mVolume += 8;
    01689                                                 break;
    01690                                             case 0xD:
    01691                                                 ch.mVolume += 16;
    01692                                                 break;
    01693                                             case 0xE:
    01694                                                 ch.mVolume = (INT8)((ch.mVolume * 3) / 2);
    01695                                                 break;
    01696                                             case 0xF:
    01697                                                 ch.mVolume <<= 1;
    01698                                                 break;
    01699                                         }
    01700
    01701                                         ch.mBaseVolume = ch.mVolume;
    01702                                     }
    01703                                 }
    01704                             }
    01705
    01706                             ch.mMultiRetrigTicker++;
    01707                             break;
    01708
    01709                         case 0x1D:  // Tremor (Txy)
    01710                             if (ch.mEffectValue != 0) ch.mTremorV = ch.mEffectValue;
    01711
    01712                             if (ch.mTremorV != 0)
    01713                             {
    01714                                 if ((UINT8)(ch.mTremorTicker %
    01715                                     ((ch.mTremorV >> 4) + (ch.mTremorV & 0xF) + 2)) <
    01716                                     (ch.mTremorV >> 4) + 1)
    01717                                     ch.mVolume = ch.mBaseVolume;
    01718                                 else
    01719                                     ch.mVolume = 0;
    01720                             }
    01721                             break;
    01722
    01723                         case 0x21:  // Extra fine portamento up/down (X1y/X2y)
    01724                             switch(ch.mEffectValue >> 4)
    01725                             {
    01726                                 case 0x1:   // Extra fine portamento up (X1y)
    01727                                     if ((ch.mEffectValue & 0xF) != 0)
    01728                                         ch.mExtraFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
    01729
    01730                                     ch.mPeriod -= ch.mExtraFinePortamentoUpV;
    01731                                     ch.mBasePeriod = ch.mPeriod;
    01732                                     break;
    01733                                 case 0x2:   // Extra fine portamento down (X2y)
    01734                                     if ((ch.mEffectValue & 0xF) != 0)
    01735                                         ch.mExtraFinePortamentoDownV = (UINT8)(ch.mEffectValue & 0xF);
    01736
    01737                                     ch.mPeriod -= ch.mExtraFinePortamentoUpV;
    01738                                     ch.mBasePeriod = ch.mPeriod;
    01739                                     break;
    01740                             }
    01741                             break;
    01742                     }
    01743
    01744                     notifyHandlers(ch);
    01745
    01746                     // Key off (Kxy)
    01747                     if ((ch.mEffectType == 0x14) || (ch.mTa.mNote == 97))
    01748                     {
    01749                         if (ch.mSustainReleased == 0)
    01750                         {
    01751                             ch.mSustainReleased = 1;
    01752                             if (ch.mVolEnvType & ENVELOPE_SUSTAIN)
    01753                                 ch.mVolEnvSpeed = 1; // Start envelope
    01754
    01755                             if (ch.mVolEnvType == 0)
    01756                                 ch.mVolume = 0;
    01757
    01758                             // FIX ME!!! PANNING ENVELOPE STUFF MISSING!!!
    01759                         }
    01760                      }
    01761                 }
    01762
    01763                 if (mPatternDelayCounterTemp != 0)
    01764                 {
    01765                     mPatternDelayCounter = mPatternDelayCounterTemp;
    01766                     mPatternDelayCounterTemp = 0;
    01767                     mPatternDelaySkip = 1;
    01768                 }
    01769             }
    01770             else if (mSong.mTempo != 0)
    01771             {
    01772                 // Tick effects
    01773                 for (chan = 0; chan < mSong.mNbChannels; chan++)
    01774                 {
    01775                     XFuXMChannel &ch = mChannels[chan];
    01776
    01777                     if (ch.mVolumeColumn != 0)
    01778                     {
    01779                         switch(ch.mVolumeColumn >> 4)
    01780                         {
    01781                         case 0x6:   // Volume slide down (-xy)
    01782                             ch.mVolume -= (ch.mVolumeColumn & 0xF);
    01783                             ch.mBaseVolume = ch.mVolume;
    01784                             break;
    01785
    01786                         case 0x7:   // Volume slide up (+xy)
    01787                             ch.mVolume += (ch.mVolumeColumn & 0xF);
    01788                             ch.mBaseVolume = ch.mVolume;
    01789                             break;
    01790
    01791                         case 0xF:   // Tone portamento (Mxy)
    01792                             if (ch.mOldPeriod != 0)
    01793                             {
    01794                                 if (ch.mDestPeriod > ch.mPeriod)
    01795                                 {
    01796                                     ch.mPeriod += (ch.mTonePortamentoV * 4);
    01797                                     if (ch.mPeriod > ch.mDestPeriod)
    01798                                         ch.mPeriod = ch.mDestPeriod;
    01799                                 }
    01800                                 else if (ch.mDestPeriod < ch.mPeriod)
    01801                                 {
    01802                                     ch.mPeriod -= (ch.mTonePortamentoV * 4);
    01803                                     if (ch.mPeriod < ch.mDestPeriod)
    01804                                         ch.mPeriod = ch.mDestPeriod;
    01805                                 }
    01806
    01807                                 ch.mBasePeriod = ch.mPeriod;
    01808                             }
    01809                             break;
    01810                         }
    01811                     }
    01812
    01813                     switch (ch.mEffectType)
    01814                     {
    01815                         case 0x0:   // Arpeggio (0xy)
    01816                             if (ch.mEffectValue != 0)
    01817                             {
    01818                                 switch (mCurrentTick % 3)
    01819                                 {
    01820                                     case 0:
    01821                                         ch.mPeriod = ch.mBasePeriod;
    01822                                         break;
    01823                                     case 1:
    01824                                         ch.mPeriod = ch.mBasePeriod - (ch.mEffectValue >> 4) * 64;
    01825                                         break;
    01826                                     case 2:
    01827                                         ch.mPeriod = ch.mBasePeriod - (ch.mEffectValue & 0xF) * 64;
    01828                                         break;
    01829                                 }
    01830                             }
    01831                             break;
    01832
    01833                         case 0x1:   // Portamento up (1xy)
    01834                             ch.mPeriod -= (ch.mPortamentoUpV * 4);
    01835                             ch.mBasePeriod = ch.mPeriod;
    01836                             break;
    01837
    01838                         case 0x2:   // Portamento down (2xy)
    01839                             ch.mPeriod += (ch.mPortamentoDownV * 4);
    01840                             ch.mBasePeriod = ch.mPeriod;
    01841                             break;
    01842
    01843                         case 0x7:   // Tremolo (7xy), FIX ME!
    01844                             if (ch.mTremoloWaveform & WAVEFORM_SINEWAVE)
    01845                                 tremoloTable = mSineWaveTable;
    01846                             else if (ch.mTremoloWaveform & WAVEFORM_SQUAREWAVE)
    01847                                 tremoloTable = mSquareWaveTable;
    01848                             else if (ch.mTremoloWaveform & WAVEFORM_RAMPDOWN)
    01849                                 tremoloTable = mRampDownTable;
    01850                             // FIX ME! Random waveform not supported
    01851
    01852                             ch.mVolume = (INT8)(ch.mBaseVolume +
    01853                                 ((tremoloTable[ch.mTremoloPointer] * ch.mTremoloDepth) >> 6));
    01854                             ch.mTremoloPointer = (UINT8)(
    01855                                 (ch.mTremoloPointer + ch.mTremoloRate) % XMFORMAT_SIZEOF_WAVEFORM);
    01856                             break;
    01857
    01858                         case 0xE:   // Extra effects (Exy)
    01859                             switch ((ch.mEffectValue >> 4))
    01860                             {
    01861                                 case 0x9:   // Retrig note (E9y)
    01862                                     if (((ch.mEffectValue & 0xF) != 0) &&
    01863                                         ((mCurrentTick % (ch.mEffectValue & 0xF)) == 0))
    01864                                     {
    01865                                         ch.mInitSample = 1;
    01866                                         initSound(ch);
    01867                                     }
    01868                                     break;
    01869
    01870                                 case 0xC:   // Note cut (ECy)
    01871                                     if (mCurrentTick == (ch.mEffectValue & 0xF))
    01872                                     {
    01873                                         ch.mVolume = 0;
    01874                                         ch.mBaseVolume = ch.mVolume;
    01875                                     }
    01876                                     break;
    01877
    01878                                 case 0xD:   // Note delay (EDy)
    01879                                     if (mCurrentTick == (ch.mEffectValue & 0xF))
    01880                                     {
    01881                                         initChannel(ch);
    01882                                     }
    01883                                     break;
    01884                             }
    01885                             break;
    01886
    01887                         case 0x19:  // Panning slide (Pxy)
    01888                             ch.mPan += (ch.mPanningSlideV >> 4);
    01889                             if (ch.mPan > 0xFF) ch.mPan = 0xFF;
    01890
    01891                             ch.mPan -= (ch.mPanningSlideV & 0xF);
    01892                             if (ch.mPan < 0) ch.mPan = 0;
    01893
    01894                             break;
    01895
    01896                         case 0x1B:  // Multi retrig note (Rxy)
    01897                             if (ch.mMultiRetrigRateV != 0)
    01898                             {
    01899                                 if ((ch.mMultiRetrigTicker % ch.mMultiRetrigRateV) == 0)
    01900                                 {
    01901                                     ch.mInitSample = 1;
    01902                                     initSound(ch);
    01903
    01904                                     if ((ch.mMultiRetrigVolumeV != 8) && (ch.mMultiRetrigTicker != 0))
    01905                                     {
    01906                                         // Don't affect volume on first tick
    01907                                         switch (ch.mMultiRetrigVolumeV)
    01908                                         {
    01909                                             case 0x1:
    01910                                                 ch.mVolume -= 1;
    01911                                                 break;
    01912                                             case 0x2:
    01913                                                 ch.mVolume -= 2;
    01914                                                 break;
    01915                                             case 0x3:
    01916                                                 ch.mVolume -= 4;
    01917                                                 break;
    01918                                             case 0x4:
    01919                                                 ch.mVolume -= 8;
    01920                                                 break;
    01921                                             case 0x5:
    01922                                                 ch.mVolume -= 16;
    01923                                                 break;
    01924                                             case 0x6:
    01925                                                 ch.mVolume = (INT8)(ch.mVolume * 2.0f / 3.0f);
    01926                                                 break;
    01927                                             case 0x7:
    01928                                                 ch.mVolume >>= 1;
    01929                                                 break;
    01930                                             case 0x9:
    01931                                                 ch.mVolume += 1;
    01932                                                 break;
    01933                                             case 0xA:
    01934                                                 ch.mVolume += 2;
    01935                                                 break;
    01936                                             case 0xB:
    01937                                                 ch.mVolume += 4;
    01938                                                 break;
    01939                                             case 0xC:
    01940                                                 ch.mVolume += 8;
    01941                                                 break;
    01942                                             case 0xD:
    01943                                                 ch.mVolume += 16;
    01944                                                 break;
    01945                                             case 0xE:
    01946                                                 ch.mVolume = (INT8)(ch.mVolume * 3.0f / 2.0f);
    01947                                                 break;
    01948                                             case 0xF:
    01949                                                 ch.mVolume <<= 1;
    01950                                                 break;
    01951                                         }
    01952
    01953                                         if (ch.mVolume > 0x40) ch.mVolume = 0x40;
    01954                                         else if (ch.mVolume < 0) ch.mVolume = 0;
    01955
    01956                                         ch.mBaseVolume = ch.mVolume;
    01957                                     }
    01958                                 }
    01959                             }
    01960
    01961                             ch.mMultiRetrigTicker++;
    01962                             break;
    01963
    01964                         case 0x1D:  // Tremor (Txy)
    01965                             if (ch.mTremorV != 0)
    01966                             {
    01967                                 if ((UINT8)(ch.mTremorTicker %
    01968                                     ((ch.mTremorV >> 4) + (ch.mTremorV & 0xF) + 2)) <
    01969                                     (ch.mTremorV >> 4) + 1)
    01970                                     ch.mVolume = ch.mBaseVolume;
    01971                                 else
    01972                                     ch.mVolume = 0;
    01973                             }
    01974
    01975                             ch.mTremorTicker++;
    01976                             break;
    01977
    01978                     }
    01979
    01980                     // Tone portamento (3xy) /
    01981                     // tone portamento + volume slide (5xy) /
    01982                     // volume column tone portamento (Mxy)
    01983                     if ((ch.mEffectType == 0x3) || (ch.mEffectType == 0x5))
    01984                     {
    01985                         if (ch.mOldPeriod != 0)
    01986                         {
    01987                             if (ch.mDestPeriod > ch.mPeriod)
    01988                             {
    01989                                 ch.mPeriod += (ch.mTonePortamentoV * 4);
    01990                                 if (ch.mPeriod > ch.mDestPeriod) ch.mPeriod = ch.mDestPeriod;
    01991                             }
    01992                             else if (ch.mDestPeriod < ch.mPeriod)
    01993                             {
    01994                                 ch.mPeriod -= (ch.mTonePortamentoV * 4);
    01995                                 if (ch.mPeriod < ch.mDestPeriod) ch.mPeriod = ch.mDestPeriod;
    01996                             }
    01997
    01998                             ch.mBasePeriod = ch.mPeriod;
    01999                         }
    02000                     }
    02001
    02002                     // Volume slide (Axy) /
    02003                     // tone portamento + volume slide (5xy) /
    02004                     // vibrato + volume slide (6xy)
    02005                     if ((ch.mEffectType == 0xA) || (ch.mEffectType == 0x5) || (ch.mEffectType == 0x6))
    02006                     {
    02007                         ch.mVolume += (ch.mVolumeSlideV >> 4);
    02008                         if (ch.mVolume > 0x40) ch.mVolume = 0x40;
    02009
    02010                         ch.mVolume -= (ch.mVolumeSlideV & 0xF);
    02011                         if (ch.mVolume < 0) ch.mVolume = 0;
    02012
    02013                         ch.mBaseVolume = ch.mVolume;
    02014                     }
    02015
    02016                     // Vibrato
    02017                     if (ch.mIsVibrato)
    02018                     {
    02019                         if (ch.mVibratoWaveform & WAVEFORM_SINEWAVE)
    02020                             vibratoTable = mSineWaveTable;
    02021                         else if (ch.mVibratoWaveform & WAVEFORM_SQUAREWAVE)
    02022                             vibratoTable = mSquareWaveTable;
    02023                         else if (ch.mVibratoWaveform & WAVEFORM_RAMPDOWN)
    02024                             vibratoTable = mRampDownTable;
    02025                         // FIX ME! Random waveform not supported
    02026
    02027                         ch.mPeriod = ch.mBasePeriod +
    02028                             ((vibratoTable[ch.mVibratoPointer] * ch.mVibratoDepth) >> 7);
    02029                         ch.mVibratoPointer = (UINT8)(
    02030                             (ch.mVibratoPointer + ch.mVibratoRate) % XMFORMAT_SIZEOF_WAVEFORM);
    02031                     }
    02032                 }
    02033             }
    02034
    02035             for (chan = 0; chan < mSong.mNbChannels; chan++)
    02036             {
    02037                 XFuXMChannel &ch = mChannels[chan];
    02038                 XFuXMInstrument *in = NULL;
    02039
    02040                 if ((ch.mInstrumentNb != -1) && (ch.mInstrumentNb < mSong.mNbInstruments))
    02041                 {
    02042                     in = &mInstruments[ch.mInstrumentNb];
    02043
    02044                     ch.mFinalOldVolume = ch.mFinalVolume;
    02045
    02046                     // Volume envelope
    02047                     if (ch.mVolEnvType & ENVELOPE_ON)
    02048                     {
    02049                         if (ch.mVolEnvPointer >= in->mVolEnvEnd)
    02050                         {
    02051                             // Not normal behavior but can happen when using
    02052                             // set envelope position (Lxy) command with a value
    02053                             // which is bigger than the last envelope point
    02054                             ch.mVolEnvPointer = in->mVolEnvEnd;
    02055                             ch.mVolEnvSpeed = 0;
    02056                         }
    02057
    02058                         ch.mVolEnvValue = in->mVolumeEnvelope[ch.mVolEnvPointer];
    02059
    02060                         if ((ch.mVolEnvType & ENVELOPE_SUSTAIN) &&
    02061                             (ch.mVolEnvPointer == ch.mVolEnvSustain) &&
    02062                             (ch.mSustainReleased == 0))
    02063                         {
    02064                             // Sustain point, stop envelope
    02065                             ch.mVolEnvSpeed = 0;
    02066                         }
    02067
    02068                         // Fix for trackers which don't follow FT2 standard in envelopes
    02069                         if (in->mVolEnvEnd != 0) ch.mVolEnvPointer += ch.mVolEnvSpeed;
    02070
    02071                         if (ch.mVolEnvType & ENVELOPE_LOOP)
    02072                         {
    02073                             // Envelope loop
    02074                             // The loop check is faulty and should check whether
    02075                             // the pointer has passed the end point instead, but
    02076                             // as the bug is in FT2, it is also here for the sake
    02077                             // of compatibility
    02078                             if ((ch.mVolEnvSpeed) && (ch.mVolEnvPointer == ch.mVolEnvLoopEnd))
    02079                                 ch.mVolEnvPointer = ch.mVolEnvLoopStart;
    02080                         }
    02081                         else
    02082                         {
    02083                             if (ch.mVolEnvPointer == in->mVolEnvEnd)
    02084                                 ch.mVolEnvSpeed = 0;
    02085                         }
    02086
    02087                         if (ch.mSustainReleased)
    02088                         {
    02089                             ch.mVolumeFadeoutValue -= (ch.mVolumeFadeout * 2);
    02090                             if (ch.mVolumeFadeoutValue < 0) ch.mVolumeFadeoutValue = 0;
    02091                         }
    02092                     } else ch.mVolEnvValue = REALf(1.0f); // No volume envelope
    02093
    02094                     // Panning envelope
    02095                     if (ch.mPanEnvType & ENVELOPE_ON)
    02096                     {
    02097                         if (ch.mPanEnvPointer >= in->mPanEnvEnd)
    02098                         {
    02099                             // Not normal behavior but can happen when using
    02100                             // set envelope position (Lxy) command with a value
    02101                             // which is bigger than the last envelope point
    02102                             ch.mPanEnvPointer = in->mPanEnvEnd;
    02103                             ch.mPanEnvSpeed = 0;
    02104                         }
    02105
    02106                         ch.mPanEnvValue = in->mPanningEnvelope[ch.mPanEnvPointer];
    02107
    02108                         if ((ch.mPanEnvType & ENVELOPE_SUSTAIN) &&
    02109                             (ch.mPanEnvPointer == ch.mPanEnvSustain) &&
    02110                             (ch.mSustainReleased == 0))
    02111                         {
    02112                             // Sustain point, stop envelope
    02113                             ch.mPanEnvSpeed = 0;
    02114                         }
    02115
    02116                         // Fix for trackers which don't follow FT2 standard in envelopes
    02117                         if (in->mPanEnvEnd != 0) ch.mPanEnvPointer += ch.mPanEnvSpeed;
    02118
    02119                         if (ch.mPanEnvType & ENVELOPE_LOOP)
    02120                         {
    02121                             // Envelope loop
    02122                             // The loop check is faulty and should check whether
    02123                             // the pointer has passed the end point instead, but
    02124                             // as the bug is in FT2, it is also here for the sake
    02125                             // of compatibility
    02126                             if ((ch.mPanEnvSpeed) && (ch.mPanEnvPointer == ch.mPanEnvLoopEnd))
    02127                                 ch.mPanEnvPointer = ch.mPanEnvLoopStart;
    02128                         }
    02129                         else
    02130                         {
    02131                             if (ch.mPanEnvPointer == in->mPanEnvEnd) ch.mPanEnvSpeed = 0;
    02132                         }
    02133                     } else ch.mPanEnvValue = 0x20;  // No panning envelope
    02134
    02135                     if (ch.mVolume > 0x40) ch.mVolume = 0x40;
    02136                     if (ch.mVolume < 0) ch.mVolume = 0;
    02137
    02138                     INT32 intVolume = (ch.mVolume * mSong.mGlobalVolume);
    02139                     REAL volumeTemp;
    02140                     volumeTemp.mValue = (intVolume << 3) + (intVolume << 1);
    02141                     ch.mFinalVolume = (volumeTemp * ch.mVolEnvValue * ch.mVolumeFadeoutValue);
    02142
    02143                     volumeTemp = (ch.mFinalVolume - ch.mFinalOldVolume);
    02144                     ch.mFinalVolumeSpeed = (volumeTemp * mVolumeRampDivOpt);
    02145
    02146 /*
    02147                     REAL volumeTemp;
    02148                     volumeTemp.mValue = (ch.mVolume * mSong.mGlobalVolume * ch.mVolumeFadeoutValue) >> 13;
    02149                     ch.mFinalVolume = (volumeTemp * ch.mVolEnvValue);
    02150
    02151                     volumeTemp = (ch.mFinalVolume - ch.mFinalOldVolume);
    02152                     ch.mFinalVolumeSpeed = (volumeTemp * mVolumeRampDivOpt);
    02153 */
    02154 /*
    02155                     FLOAT32 volumeReal;
    02156                     volumeReal = (((FLOAT32)ch.mVolume / 65.0f) * (FLOAT32)ch.mVolEnvValue *
    02157                         (FLOAT32)ch.mVolumeFadeoutValue * ((FLOAT32)mSong.mGlobalVolume / 65.0f));
    02158
    02159                     ch.mFinalVolume = REALf(volumeReal);
    02160
    02161                     ch.mFinalVolumeSpeed = (ch.mFinalVolume - ch.mFinalOldVolume) / REALf(32);
    02162 */
    02163 /*
    02164                     volumeReal = (ch.mVolume * (FLOAT32)ch.mVolEnvValue *
    02165                         ch.mVolumeFadeoutValue * mSong.mGlobalVolume) *
    02166                         VOLUME_DIV_OPT;
    02167
    02168                     ch.mFinalVolume = (INT32)volumeReal;
    02169
    02170                     ch.mFinalVolumeSpeed = (INT32)((ch.mFinalVolume - ch.mFinalOldVolume) *
    02171                         VOLUME_RAMP_WIDTH_OPT);
    02172 */
    02173
    02174                     ch.mFinalPan = (INT16)(ch.mPan + (((ch.mPanEnvValue - 0x20) *
    02175                           (0x80 - ABS(ch.mPan - 0x80))) >> 5));
    02176                     if (ch.mFinalPan > 0xFF) ch.mFinalPan = 0xFF;
    02177                     else if (ch.mFinalPan < 0) ch.mFinalPan = 0;
    02178
    02179                     ch.mSpeed = getSpeed(ch.mPeriod, mSamplingRate);
    02180                 }
    02181             }
    02182         }
    02183
    02184         ticksLeft = (mSamplesPerTick - mSamplePointer);
    02185         indicesLeft = (aSamples - index);
    02186
    02187         if (ticksLeft < indicesLeft) samplesToRender = ticksLeft;
    02188         else samplesToRender = indicesLeft;
    02189
    02190         INT startChan = 0;
    02191         INT endChan = mSong.mNbChannels;
    02192         if (mFlags & XFCAUDIO_16BIT)    // 16bit
    02193         {
    02194             if (mFlags & XFCAUDIO_STEREO)   // 16bit stereo
    02195             {
    02196                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
    02197                 {
    02198                     cLeft = cRight = 0;
    02199
    02200                     for (chan = startChan; chan < endChan; chan++)
    02201                     {
    02202                         XFuXMChannel &ch = mChannels[chan];
    02203
    02204                         if (ch.mIsSample)
    02205                         {
    02206                             delta = ch.mPointer & (FP_VALUE - 1);
    02207
    02208                             val1 = 0;
    02209                             val2 = 0;
    02210
    02211                             if (ch.mCurrentSample.m16Bit)
    02212                             {
    02213                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02214
    02215                                 if (ch.mLoop == 0)
    02216                                 {
    02217                                     interpolateLinear16(ch, val1, val2);
    02218                                     addPointer(ch);
    02219                                 }
    02220                                 else
    02221                                 {
    02222                                     temp = (ch.mPointer + FP_VALUE);
    02223
    02224                                     if (ch.mLoop == LOOP_FORWARD)
    02225                                     {
    02226                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
    02227                                         addPointerForwardLoop(ch);
    02228                                     }
    02229                                     else if (ch.mLoop == LOOP_PINGPONG)
    02230                                     {
    02231                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
    02232                                         addPointerBidirectionalLoop(ch);
    02233                                     }
    02234                                 }
    02235                             }
    02236                             else
    02237                             {
    02238                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02239
    02240                                 if (ch.mLoop == 0)
    02241                                 {
    02242                                     interpolateLinear8(ch, val1, val2);
    02243                                     addPointer(ch);
    02244                                 }
    02245                                 else
    02246                                 {
    02247                                     temp = (ch.mPointer + FP_VALUE);
    02248
    02249                                     if (ch.mLoop == LOOP_FORWARD)
    02250                                     {
    02251                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
    02252                                         addPointerForwardLoop(ch);
    02253                                     }
    02254                                     else if (ch.mLoop == LOOP_PINGPONG)
    02255                                     {
    02256                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
    02257                                         addPointerBidirectionalLoop(ch);
    02258                                     }
    02259                                 }
    02260
    02261                                 val1 <<= 8;
    02262                                 val2 <<= 8;
    02263                             }
    02264
    02265                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
    02266
    02267                             value = (INT16)(value * ch.mFinalOldVolume);
    02268                             cLeft += ((value * (0xFF - (UINT8)ch.mFinalPan)) >> 8);
    02269                             cRight += ((value * (UINT8)ch.mFinalPan) >> 8);
    02270
    02271                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
    02272                         }
    02273                     }
    02274
    02275                     if (cLeft < -32768) cLeft = -32768;
    02276                     else if (cLeft > 32767) cLeft = 32767;
    02277                     if (cRight < -32768) cRight = -32768;
    02278                     else if (cRight > 32767) cRight = 32767;
    02279
    02280                     *((INT16 *)aBuffer + (targetOffset << 1)) = (INT16)(cLeft ^ mTgtXor);
    02281                     *((INT16 *)aBuffer + (targetOffset << 1) + 1) = (INT16)(cRight ^ mTgtXor);
    02282
    02283                     targetOffset++;
    02284                     if (targetOffset == aTargetSamples) targetOffset = 0;
    02285
    02286                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
    02287                 }
    02288             }
    02289             else    // 16bit mono
    02290             {
    02291                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
    02292                 {
    02293                     cLeft = 0;
    02294
    02295                     for (chan = startChan; chan < endChan; chan++)
    02296                     {
    02297                         XFuXMChannel &ch = mChannels[chan];
    02298
    02299                         if (ch.mIsSample)
    02300                         {
    02301                             delta = ch.mPointer & (FP_VALUE - 1);
    02302
    02303                             val1 = 0;
    02304                             val2 = 0;
    02305
    02306                             if (ch.mCurrentSample.m16Bit)
    02307                             {
    02308                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02309
    02310                                 if (ch.mLoop == 0)
    02311                                 {
    02312                                     interpolateLinear16(ch, val1, val2);
    02313                                     addPointer(ch);
    02314                                 }
    02315                                 else
    02316                                 {
    02317                                     temp = (ch.mPointer + FP_VALUE);
    02318
    02319                                     if (ch.mLoop == LOOP_FORWARD)
    02320                                     {
    02321                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
    02322                                         addPointerForwardLoop(ch);
    02323                                     }
    02324                                     else if (ch.mLoop == LOOP_PINGPONG)
    02325                                     {
    02326                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
    02327                                         addPointerBidirectionalLoop(ch);
    02328                                     }
    02329                                 }
    02330                             }
    02331                             else
    02332                             {
    02333                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02334
    02335                                 if (ch.mLoop == 0)
    02336                                 {
    02337                                     interpolateLinear8(ch, val1, val2);
    02338                                     addPointer(ch);
    02339                                 }
    02340                                 else
    02341                                 {
    02342                                     temp = (ch.mPointer + FP_VALUE);
    02343
    02344                                     if (ch.mLoop == LOOP_FORWARD)
    02345                                     {
    02346                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
    02347                                         addPointerForwardLoop(ch);
    02348                                     }
    02349                                     else if (ch.mLoop == LOOP_PINGPONG)
    02350                                     {
    02351                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
    02352                                         addPointerBidirectionalLoop(ch);
    02353                                     }
    02354                                 }
    02355
    02356                                 val1 <<= 8;
    02357                                 val2 <<= 8;
    02358                             }
    02359
    02360                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
    02361
    02362                             cLeft += (INT16)(value * ch.mFinalOldVolume);
    02363
    02364                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
    02365                         }
    02366                     }
    02367
    02368                     if (cLeft > 32767) cLeft = 32767;
    02369                     else if (cLeft < -32768) cLeft = -32768;
    02370
    02371                     *((INT16 *)aBuffer + targetOffset) = (INT16)(cLeft ^ mTgtXor);
    02372
    02373                     targetOffset++;
    02374                     if (targetOffset == aTargetSamples) targetOffset = 0;
    02375
    02376                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
    02377                 }
    02378             }
    02379         }
    02380         else    // 8bit
    02381         {
    02382             if (mFlags & XFCAUDIO_STEREO)   // 8bit stereo
    02383             {
    02384                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
    02385                 {
    02386                     cLeft = cRight = 0;
    02387
    02388                     for (chan = startChan; chan < endChan; chan++)
    02389                     {
    02390                         XFuXMChannel &ch = mChannels[chan];
    02391
    02392                         if (ch.mIsSample)
    02393                         {
    02394                             delta = ch.mPointer & (FP_VALUE - 1);
    02395
    02396                             val1 = 0;
    02397                             val2 = 0;
    02398
    02399                             if (ch.mCurrentSample.m16Bit)
    02400                             {
    02401                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02402
    02403                                 if (ch.mLoop == 0)
    02404                                 {
    02405                                     interpolateLinear16(ch, val1, val2);
    02406                                     addPointer(ch);
    02407                                 }
    02408                                 else
    02409                                 {
    02410                                     temp = (ch.mPointer + FP_VALUE);
    02411
    02412                                     if (ch.mLoop == LOOP_FORWARD)
    02413                                     {
    02414                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
    02415                                         addPointerForwardLoop(ch);
    02416                                     }
    02417                                     else if (ch.mLoop == LOOP_PINGPONG)
    02418                                     {
    02419                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
    02420                                         addPointerBidirectionalLoop(ch);
    02421                                     }
    02422                                 }
    02423
    02424                                 val1 >>= 8;
    02425                                 val2 >>= 8;
    02426                             }
    02427                             else
    02428                             {
    02429                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02430
    02431                                 if (ch.mLoop == 0)
    02432                                 {
    02433                                     interpolateLinear8(ch, val1, val2);
    02434                                     addPointer(ch);
    02435                                 }
    02436                                 else
    02437                                 {
    02438                                     temp = (ch.mPointer + FP_VALUE);
    02439
    02440                                     if (ch.mLoop == LOOP_FORWARD)
    02441                                     {
    02442                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
    02443                                         addPointerForwardLoop(ch);
    02444                                     }
    02445                                     else if (ch.mLoop == LOOP_PINGPONG)
    02446                                     {
    02447                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
    02448                                         addPointerBidirectionalLoop(ch);
    02449                                     }
    02450                                 }
    02451                             }
    02452
    02453                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
    02454
    02455                             value = (INT8)(value * ch.mFinalOldVolume);
    02456                             cLeft += ((value * (0xFF - (UINT8)ch.mFinalPan)) >> 8);
    02457                             cRight += ((value * (UINT8)ch.mFinalPan) >> 8);
    02458
    02459                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
    02460                         }
    02461                     }
    02462
    02463                     if (cLeft < -128) cLeft = -128;
    02464                     else if (cLeft > 127) cLeft = 127;
    02465                     if (cRight < -128) cRight = -128;
    02466                     else if (cRight > 127) cRight = 127;
    02467
    02468                     *((INT8 *)aBuffer + (targetOffset << 1)) = (INT8)(cLeft ^ mTgtXor);
    02469                     *((INT8 *)aBuffer + (targetOffset << 1) + 1) = (INT8)(cRight ^ mTgtXor);
    02470
    02471                     targetOffset++;
    02472                     if (targetOffset == aTargetSamples) targetOffset = 0;
    02473
    02474                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
    02475                 }
    02476             }
    02477             else    // 8bit mono
    02478             {
    02479                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
    02480                 {
    02481                     cLeft = 0;
    02482
    02483                     for (chan = startChan; chan < endChan; chan++)
    02484                     {
    02485                         XFuXMChannel &ch = mChannels[chan];
    02486
    02487                         if (ch.mIsSample)
    02488                         {
    02489                             delta = ch.mPointer & (FP_VALUE - 1);
    02490
    02491                             val1 = 0;
    02492                             val2 = 0;
    02493
    02494                             if (ch.mCurrentSample.m16Bit)
    02495                             {
    02496                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02497
    02498                                 if (ch.mLoop == 0)
    02499                                 {
    02500                                     interpolateLinear16(ch, val1, val2);
    02501                                     addPointer(ch);
    02502                                 }
    02503                                 else
    02504                                 {
    02505                                     temp = (ch.mPointer + FP_VALUE);
    02506
    02507                                     if (ch.mLoop == LOOP_FORWARD)
    02508                                     {
    02509                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
    02510                                         addPointerForwardLoop(ch);
    02511                                     }
    02512                                     else if (ch.mLoop == LOOP_PINGPONG)
    02513                                     {
    02514                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
    02515                                         addPointerBidirectionalLoop(ch);
    02516                                     }
    02517                                 }
    02518
    02519                                 val1 >>= 8;
    02520                                 val2 >>= 8;
    02521                             }
    02522                             else
    02523                             {
    02524                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
    02525
    02526                                 if (ch.mLoop == 0)
    02527                                 {
    02528                                     interpolateLinear8(ch, val1, val2);
    02529                                     addPointer(ch);
    02530                                 }
    02531                                 else
    02532                                 {
    02533                                     temp = (ch.mPointer + FP_VALUE);
    02534
    02535                                     if (ch.mLoop == LOOP_FORWARD)
    02536                                     {
    02537                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
    02538                                         addPointerForwardLoop(ch);
    02539                                     }
    02540                                     else if (ch.mLoop == LOOP_PINGPONG)
    02541                                     {
    02542                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
    02543                                         addPointerBidirectionalLoop(ch);
    02544                                     }
    02545                                 }
    02546                             }
    02547
    02548                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
    02549
    02550                             cLeft += (INT8)(value * ch.mFinalOldVolume);
    02551
    02552                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
    02553                         }
    02554                     }
    02555
    02556                     if (cLeft > 127) cLeft = 127;
    02557                     else if (cLeft < -128) cLeft = -128;
    02558
    02559                     *((INT8 *)aBuffer + targetOffset) = (INT8)(cLeft ^ mTgtXor);
    02560
    02561                     targetOffset++;
    02562                     if (targetOffset == aTargetSamples) targetOffset = 0;
    02563
    02564                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
    02565                 }
    02566             }
    02567         }
    02568
    02569         mSamplePointer += samplesToRender;
    02570     }
    02571
    02572     mTotalTicks += aSamples;
    02573
    02574     return 1;
    02575 }
    02576
    02577 // For MSVC
    02578 #pragma warning(default:4244)
    02579
    02580
    02581 XFuXMPlayer::XFuXMPlayer(FLOAT32 aSamplingRate, UINT32 aFlags)
    02582 {
    02583     mSamplingRate = aSamplingRate;
    02584     mFlags = aFlags;
    02585
    02586     mTgtXor = 0;
    02587     if (!(mFlags & XFCAUDIO_SIGNED))
    02588     {
    02589         if (mFlags & XFCAUDIO_16BIT) mTgtXor = -32768;
    02590         else mTgtXor = -128;
    02591     }
    02592
    02593     /* Sinewave table */
    02594     mSineWaveTable[0] = 0;
    02595     mSineWaveTable[1] = 24;
    02596     mSineWaveTable[2] = 49;
    02597     mSineWaveTable[3] = 74;
    02598     mSineWaveTable[4] = 97;
    02599     mSineWaveTable[5] = 120;
    02600     mSineWaveTable[6] = 141;
    02601     mSineWaveTable[7] = 161;
    02602     mSineWaveTable[8] = 180;
    02603     mSineWaveTable[9] = 197;
    02604     mSineWaveTable[10] = 212;
    02605     mSineWaveTable[11] = 224;
    02606     mSineWaveTable[12] = 235;
    02607     mSineWaveTable[13] = 244;
    02608     mSineWaveTable[14] = 250;
    02609     mSineWaveTable[15] = 253;
    02610     mSineWaveTable[16] = 255;
    02611     mSineWaveTable[17] = 253;
    02612     mSineWaveTable[18] = 250;
    02613     mSineWaveTable[19] = 244;
    02614     mSineWaveTable[20] = 235;
    02615     mSineWaveTable[21] = 224;
    02616     mSineWaveTable[22] = 212;
    02617     mSineWaveTable[23] = 197;
    02618     mSineWaveTable[24] = 180;
    02619     mSineWaveTable[25] = 161;
    02620     mSineWaveTable[26] = 141;
    02621     mSineWaveTable[27] = 120;
    02622     mSineWaveTable[28] = 97;
    02623     mSineWaveTable[29] = 74;
    02624     mSineWaveTable[30] = 49;
    02625     mSineWaveTable[31] = 24;
    02626
    02627     INT i;
    02628
    02629     for (i = 32; i < 64; i++)
    02630     {
    02631         mSineWaveTable[i] = (INT16)-mSineWaveTable[i - 32];
    02632     }
    02633
    02634     /* Squarewave table */
    02635     for (i = 0; i < 32; i++) mSquareWaveTable[i] = -255;
    02636     for (i = 32; i < 64; i++) mSquareWaveTable[i] = 255;
    02637
    02638     /* Ramp up/down tables */
    02639     for (i = 0; i < 32; i++)
    02640     {
    02641         mRampUpTable[i] = (INT16)(255.0f - (FLOAT32)i * (510.0f / 32.0f));
    02642         mRampUpTable[i + 32] = (INT16)(255.0f - (FLOAT32)i * (510.0f / 32.0f));
    02643
    02644         mRampDownTable[i] = (INT16)(-255.0f + (FLOAT32)i * (510.0f / 32.0f));
    02645         mRampDownTable[i + 32] =
    02646             (INT16)(-255.0f + (FLOAT32)i * (510.0f / 32.0f));
    02647     }
    02648
    02649     mSong.mOrderTable = NULL;
    02650     mXMPatternHeaders = NULL;
    02651     mPatternData = NULL;
    02652     mInstruments = NULL;
    02653     mChannels = NULL;
    02654
    02655     mEventHandlers = NULL;
    02656 }
    02657
    02658
    02659 XFuXMPlayer::~XFuXMPlayer()
    02660 {
    02661     INT i, j;
    02662
    02663     delete[] mSong.mOrderTable;
    02664
    02665     delete[] mXMPatternHeaders;
    02666
    02667     if (mPatternData != NULL)
    02668     {
    02669         for (i = 0; i < mSong.mNbPatterns; i++)
    02670         {
    02671             delete[] mPatternData[i].mData;
    02672             delete[] mPatternData[i].mRows;
    02673         }
    02674
    02675         delete[] mPatternData;
    02676     }
    02677
    02678     if (mInstruments != NULL)
    02679     {
    02680         for (i = 0; i < mSong.mNbInstruments; i++)
    02681         {
    02682             XFuXMInstrument &ins = mInstruments[i];
    02683
    02684             if (ins.mSamples != NULL)
    02685             {
    02686                 for (j = 0; j < ins.mNbSamples; j++)
    02687                 {
    02688                     delete[] (INT8 *)ins.mSamples[j].mOffset;
    02689                 }
    02690
    02691                 delete[] ins.mSamples;
    02692             }
    02693         }
    02694
    02695         delete[] mInstruments;
    02696     }
    02697
    02698     delete[] mChannels;
    02699
    02700     delete mEventHandlers;
    02701 }
    02702
    02703
    02704 XFuXMPlayer * XFuXMPlayer::create(const CHAR *aTunename, FLOAT32 aSampleRate, UINT32 aFlags)
    02705 {
    02706     XFcFile *textout = NULL;
    02707
    02708     XFuXMPlayer *pl = new XFuXMPlayer(aSampleRate, aFlags);
    02709
    02710     if (pl != NULL)
    02711     {
    02712         pl->initialize(aSampleRate, aFlags, 1.0, 0.5, 0);
    02713
    02714         pl->mEventHandlers = new XFcLinkedList<XFuXMPlayerEventHandlerSlot>();
    02715
    02716         if (pl->mEventHandlers == NULL)
    02717         {
    02718             delete pl;
    02719             return NULL;
    02720         }
    02721
    02722 #ifdef OUTPUT_XM_INFO
    02723         XFuXMFormatAtom ta;
    02724
    02725         textout = XFcFile::open("xmoutput.txt","wt");
    02726 #endif
    02727
    02728         if (pl->loadXM(aTunename, textout) != 0)
    02729         {
    02730             // file not found
    02731             delete pl;
    02732             return NULL;
    02733         }
    02734
    02735 #ifdef OUTPUT_XM_INFO
    02736         pl->dumpSongParameters(textout);
    02737
    02738         pl->mPatternNb = -1;
    02739         INT i;
    02740         for (i = 0; i < pl->mXMHeader.mNbPatterns; i++)
    02741         {
    02742             pl->mPatternNb++;
    02743             if (pl->mXMPatternHeaders[i].mSize > 0)
    02744             {
    02745                 debugPrint(textout, "* Pattern: %02X\n", pl->mPatternNb);
    02746                 {
    02747                     INT row, channel;
    02748                     pl->mPpoint = 0;
    02749                     for (row = 0; row < pl->mXMPatternHeaders[i].mNbRows; row++)
    02750                     {
    02751                         debugPrint(textout, "%02X: ", row);
    02752                         for (channel = 0; channel < pl->mXMHeader.mNbChannels; channel++)
    02753                         {
    02754                             ta = pl->getAtom();
    02755
    02756                             if (ta.mNote == 0)
    02757                             {
    02758                                 if (ta.mVolume != 0)
    02759                                     debugPrint(textout, "--- %02X %02X %1X%02X ; ",
    02760                                                ta.mInstrumentNb, ta.mVolume - 0x10,
    02761                                                ta.mEffectType, ta.mEffectValue);
    02762                                 else
    02763                                     debugPrint(textout, "--- %02X -- %1X%02X ; ",
    02764                                                ta.mInstrumentNb, ta.mEffectType,
    02765                                                ta.mEffectValue);
    02766                             }
    02767                             else
    02768                             {
    02769                                 if (ta.mVolume != 0)
    02770                                     debugPrint(textout,
    02771                                                "%s%1d %02X %02X %1X%02X ; ",
    02772                                                notes[(ta.mNote - 1) % 12],
    02773                                                (INT)((ta.mNote - 1) / 12),
    02774                                                ta.mInstrumentNb, ta.mVolume - 0x10,
    02775                                                ta.mEffectType, ta.mEffectValue);
    02776                                 else
    02777                                     debugPrint(textout, "%s%1d %02X -- %1X%02X ; ",
    02778                                                notes[(ta.mNote - 1) % 12],
    02779                                                (INT)((ta.mNote - 1) / 12),
    02780                                                ta.mInstrumentNb, ta.mEffectType,
    02781                                                ta.mEffectValue);
    02782                             }
    02783                         }
    02784
    02785                         debugPrint(textout, "\n");
    02786                     }
    02787                 }
    02788             }
    02789         }
    02790
    02791         if (textout != NULL) textout->close();
    02792 #endif
    02793
    02794         pl->initSong(0);
    02795         pl->mVolumeRampDivOpt = REALf(1.0f / VOLUME_RAMP_WIDTH);
    02796     }
    02797
    02798     return pl;
    02799 }
    02800

|  | X-Forge Documentation Confidential Copyright © 2002-2003 Fathammer |  | Documentation generated with doxygen by Dimitri van Heesch