| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582 |
- //
- // Urho3D Engine
- // Copyright (c) 2008-2011 Lasse Öörni
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- // Original MOD & XM playback code from JUDAS Soundsystem
- // Copyright (c) 1997 Lasse Öörni & Olli Niemitalo
- #include "Precompiled.h"
- #include "Audio.h"
- #include "Channel.h"
- #include "Deserializer.h"
- #include "Profiler.h"
- #include "Sound.h"
- #include "XM.h"
- #include <cstring>
- #include "DebugNew.h"
- static const int ENV_ON = 1;
- static const int ENV_SUSTAIN = 2;
- static const int ENV_LOOP = 4;
- static const int SMP_LOOP = 1;
- static const int SMP_PINGPONGLOOP = 2;
- static const int SMP_16BIT = 16;
- static const int MAX_CHANNELS = 32;
- static const int MAX_PATTERNS = 256;
- static const int MAX_INSTRUMENTS = 128;
- static const int MAX_SAMPLES = 16;
- static const int KEYOFF = 0x61;
- const unsigned XM::sLinearFreqTable[] =
- {
- 535232, 534749, 534266, 533784, 533303, 532822, 532341, 531861, 531381, 530902,
- 530423, 529944, 529466, 528988, 528511, 528034, 527558, 527082, 526607, 526131,
- 525657, 525183, 524709, 524236, 523763, 523290, 522818, 522346, 521875, 521404,
- 520934, 520464, 519994, 519525, 519057, 518588, 518121, 517653, 517186, 516720,
- 516253, 515788, 515322, 514858, 514393, 513929, 513465, 513002, 512539, 512077,
- 511615, 511154, 510692, 510232, 509771, 509312, 508852, 508393, 507934, 507476,
- 507018, 506561, 506104, 505647, 505191, 504735, 504280, 503825, 503371, 502917,
- 502463, 502010, 501557, 501104, 500652, 500201, 499749, 499298, 498848, 498398,
- 497948, 497499, 497050, 496602, 496154, 495706, 495259, 494812, 494366, 493920,
- 493474, 493029, 492585, 492140, 491696, 491253, 490809, 490367, 489924, 489482,
- 489041, 488600, 488159, 487718, 487278, 486839, 486400, 485961, 485522, 485084,
- 484647, 484210, 483773, 483336, 482900, 482465, 482029, 481595, 481160, 480726,
- 480292, 479859, 479426, 478994, 478562, 478130, 477699, 477268, 476837, 476407,
- 475977, 475548, 475119, 474690, 474262, 473834, 473407, 472979, 472553, 472126,
- 471701, 471275, 470850, 470425, 470001, 469577, 469153, 468730, 468307, 467884,
- 467462, 467041, 466619, 466198, 465778, 465358, 464938, 464518, 464099, 463681,
- 463262, 462844, 462427, 462010, 461593, 461177, 460760, 460345, 459930, 459515,
- 459100, 458686, 458272, 457859, 457446, 457033, 456621, 456209, 455797, 455386,
- 454975, 454565, 454155, 453745, 453336, 452927, 452518, 452110, 451702, 451294,
- 450887, 450481, 450074, 449668, 449262, 448857, 448452, 448048, 447644, 447240,
- 446836, 446433, 446030, 445628, 445226, 444824, 444423, 444022, 443622, 443221,
- 442821, 442422, 442023, 441624, 441226, 440828, 440430, 440033, 439636, 439239,
- 438843, 438447, 438051, 437656, 437261, 436867, 436473, 436079, 435686, 435293,
- 434900, 434508, 434116, 433724, 433333, 432942, 432551, 432161, 431771, 431382,
- 430992, 430604, 430215, 429827, 429439, 429052, 428665, 428278, 427892, 427506,
- 427120, 426735, 426350, 425965, 425581, 425197, 424813, 424430, 424047, 423665,
- 423283, 422901, 422519, 422138, 421757, 421377, 420997, 420617, 420237, 419858,
- 419479, 419101, 418723, 418345, 417968, 417591, 417214, 416838, 416462, 416086,
- 415711, 415336, 414961, 414586, 414212, 413839, 413465, 413092, 412720, 412347,
- 411975, 411604, 411232, 410862, 410491, 410121, 409751, 409381, 409012, 408643,
- 408274, 407906, 407538, 407170, 406803, 406436, 406069, 405703, 405337, 404971,
- 404606, 404241, 403876, 403512, 403148, 402784, 402421, 402058, 401695, 401333,
- 400970, 400609, 400247, 399886, 399525, 399165, 398805, 398445, 398086, 397727,
- 397368, 397009, 396651, 396293, 395936, 395579, 395222, 394865, 394509, 394153,
- 393798, 393442, 393087, 392733, 392378, 392024, 391671, 391317, 390964, 390612,
- 390259, 389907, 389556, 389204, 388853, 388502, 388152, 387802, 387452, 387102,
- 386753, 386404, 386056, 385707, 385359, 385012, 384664, 384317, 383971, 383624,
- 383278, 382932, 382587, 382242, 381897, 381552, 381208, 380864, 380521, 380177,
- 379834, 379492, 379149, 378807, 378466, 378124, 377783, 377442, 377102, 376762,
- 376422, 376082, 375743, 375404, 375065, 374727, 374389, 374051, 373714, 373377,
- 373040, 372703, 372367, 372031, 371695, 371360, 371025, 370690, 370356, 370022,
- 369688, 369355, 369021, 368688, 368356, 368023, 367691, 367360, 367028, 366697,
- 366366, 366036, 365706, 365376, 365046, 364717, 364388, 364059, 363731, 363403,
- 363075, 362747, 362420, 362093, 361766, 361440, 361114, 360788, 360463, 360137,
- 359813, 359488, 359164, 358840, 358516, 358193, 357869, 357547, 357224, 356902,
- 356580, 356258, 355937, 355616, 355295, 354974, 354654, 354334, 354014, 353695,
- 353376, 353057, 352739, 352420, 352103, 351785, 351468, 351150, 350834, 350517,
- 350201, 349885, 349569, 349254, 348939, 348624, 348310, 347995, 347682, 347368,
- 347055, 346741, 346429, 346116, 345804, 345492, 345180, 344869, 344558, 344247,
- 343936, 343626, 343316, 343006, 342697, 342388, 342079, 341770, 341462, 341154,
- 340846, 340539, 340231, 339924, 339618, 339311, 339005, 338700, 338394, 338089,
- 337784, 337479, 337175, 336870, 336566, 336263, 335959, 335656, 335354, 335051,
- 334749, 334447, 334145, 333844, 333542, 333242, 332941, 332641, 332341, 332041,
- 331741, 331442, 331143, 330844, 330546, 330247, 329950, 329652, 329355, 329057,
- 328761, 328464, 328168, 327872, 327576, 327280, 326985, 326690, 326395, 326101,
- 325807, 325513, 325219, 324926, 324633, 324340, 324047, 323755, 323463, 323171,
- 322879, 322588, 322297, 322006, 321716, 321426, 321136, 320846, 320557, 320267,
- 319978, 319690, 319401, 319113, 318825, 318538, 318250, 317963, 317676, 317390,
- 317103, 316817, 316532, 316246, 315961, 315676, 315391, 315106, 314822, 314538,
- 314254, 313971, 313688, 313405, 313122, 312839, 312557, 312275, 311994, 311712,
- 311431, 311150, 310869, 310589, 310309, 310029, 309749, 309470, 309190, 308911,
- 308633, 308354, 308076, 307798, 307521, 307243, 306966, 306689, 306412, 306136,
- 305860, 305584, 305308, 305033, 304758, 304483, 304208, 303934, 303659, 303385,
- 303112, 302838, 302565, 302292, 302019, 301747, 301475, 301203, 300931, 300660,
- 300388, 300117, 299847, 299576, 299306, 299036, 298766, 298497, 298227, 297958,
- 297689, 297421, 297153, 296884, 296617, 296349, 296082, 295815, 295548, 295281,
- 295015, 294749, 294483, 294217, 293952, 293686, 293421, 293157, 292892, 292628,
- 292364, 292100, 291837, 291574, 291311, 291048, 290785, 290523, 290261, 289999,
- 289737, 289476, 289215, 288954, 288693, 288433, 288173, 287913, 287653, 287393,
- 287134, 286875, 286616, 286358, 286099, 285841, 285583, 285326, 285068, 284811,
- 284554, 284298, 284041, 283785, 283529, 283273, 283017, 282762, 282507, 282252,
- 281998, 281743, 281489, 281235, 280981, 280728, 280475, 280222, 279969, 279716,
- 279464, 279212, 278960, 278708, 278457, 278206, 277955, 277704, 277453, 277203,
- 276953, 276703, 276453, 276204, 275955, 275706, 275457, 275209, 274960, 274712,
- 274465, 274217, 273970, 273722, 273476, 273229, 272982, 272736, 272490, 272244,
- 271999, 271753, 271508, 271263, 271018, 270774, 270530, 270286, 270042, 269798,
- 269555, 269312, 269069, 268826, 268583, 268341, 268099, 267857
- };
- const unsigned short XM::sAmigaFreqTable[] =
- {
- 907, 900, 894, 887, 881, 875, 868, 862, 856, 850, 844, 838, 832, 826, 820, 814,
- 808, 802, 796, 791, 785, 779, 774, 768, 762, 757, 752, 746, 741, 736, 730, 725,
- 720, 715, 709, 704, 699, 694, 689, 684, 678, 675, 670, 665, 660, 655, 651, 646,
- 640, 636, 632, 628, 623, 619, 614, 610, 604, 601, 597, 592, 588, 584, 580, 575,
- 570, 567, 563, 559, 555, 551, 547, 543, 538, 535, 532, 528, 524, 520, 516, 513,
- 508, 505, 502, 498, 494, 491, 487, 484, 480, 477, 474, 470, 467, 463, 460, 457,
- 453, 450, 447, 443, 440, 437, 434, 431, 428
- };
- const signed char XM::sRetrigAddTable[] =
- {
- 0, -1, -2, -4, -8, -16, 0, 0, 0, +1, +2, +4, +8, +16, 0, 0
- };
- const signed char XM::sRetrigMulTable[] =
- {
- 0, 0, 0, 0, 0, 0, 11, 8, 0, 0, 0, 0, 0, 0, 24, 32
- };
- const XMNote XM::sEmptyNote = {0, 0, 0, 0, 0};
- XM::XM(Audio* audio, const std::string& name) :
- Song(audio, name),
- mPos(0)
- {
- }
- XM::~XM()
- {
- release();
- }
- void XM::load(Deserializer& source, ResourceCache* cache)
- {
- PROFILE(XM_Load);
-
- release();
-
- unsigned pos;
- unsigned memoryUse = 0;
-
- // Read in the identification
- memset(&mXMId, 0, sizeof mXMId);
- source.read(&mXMId.mId, 17);
- source.read(&mXMId.mModName, 20);
- mXMId.mIdByte = source.readUByte();
- source.read(&mXMId.mTrackerName, 20);
- mXMId.mVersion = source.readUShort();
- memoryUse += sizeof mXMId;
-
- // Check that it's an XM and the version is correct
- if ((mXMId.mIdByte != 0x1a) || (memcmp("Extended Module:", mXMId.mId, 16)))
- EXCEPTION("Could not determine XM format from " + source.getName());
-
- mXMId.mIdByte = 0x0; // Serves as the songmName endzero from now on
- if (mXMId.mVersion < 0x103)
- EXCEPTION("Unsupported XM data version in " + source.getName());
-
- // Read in the header & orderlist
- pos = source.getPosition();
- mXMHeader.mHeaderSize = source.readUInt();
- mXMHeader.mSongLength = source.readUShort();
- mXMHeader.mRestartPos = source.readUShort();
- mXMHeader.mNumChannels = source.readUShort();
- mXMHeader.mNumPatterns = source.readUShort();
- mXMHeader.mNumInstruments = source.readUShort();
- mXMHeader.mUseLinear = source.readUShort();
- mXMHeader.mDefaultTickTempo = source.readUShort();
- mXMHeader.mDefaultBpmTempo = source.readUShort();
- source.read(mXMHeader.mOrder, 256);
- memoryUse += sizeof mXMHeader;
-
- // Create tracks
- mTracks.resize(mXMHeader.mNumChannels);
-
- // Skip to next section
- source.seek(pos + mXMHeader.mHeaderSize);
-
- // Load the patterns
- mPatterns.resize(mXMHeader.mNumPatterns);
- XMPackedPattern loadPattern;
- for (unsigned i = 0; i < mXMHeader.mNumPatterns; ++i)
- {
- // Load pattern header
- pos = source.getPosition();
- loadPattern.mHeaderSize = source.readUInt();
- loadPattern.mPackingType = source.readUByte();
- loadPattern.mRows = source.readUShort();
- loadPattern.mPackSize = source.readUShort();
- // Skip to next section
- source.seek(pos + loadPattern.mHeaderSize);
-
- // Allocate memory for unpacked pattern & clear
- mPatterns[i].mRows = loadPattern.mRows;
- unsigned patternSize = 5 * loadPattern.mRows * mXMHeader.mNumChannels;
- mPatterns[i].mData = new unsigned char[patternSize];
- memset(mPatterns[i].mData.getPtr(), 0, patternSize);
- memoryUse += patternSize;
-
- if (loadPattern.mPackSize)
- {
- SharedArrayPtr<unsigned char> packBuffer(new unsigned char[loadPattern.mPackSize]);
- source.read(packBuffer.getPtr(), loadPattern.mPackSize);
-
- unsigned char* packPtr = packBuffer.getPtr();
- unsigned char* unpackPtr = mPatterns[i].mData.getPtr();
- unsigned packLeft = loadPattern.mPackSize;
-
- while (packLeft)
- {
- unsigned char control = *packPtr++;
- --packLeft;
- // Packed?
- if (control & 0x80)
- {
- // Note?
- if (control & 0x01)
- {
- *unpackPtr++ = *packPtr++;
- --packLeft;
- }
- else ++unpackPtr;
- // Instrument?
- if (control & 0x02)
- {
- *unpackPtr++ = *packPtr++;
- --packLeft;
- }
- else ++unpackPtr;
- // Volume column?
- if (control & 0x04)
- {
- *unpackPtr++ = *packPtr++;
- --packLeft;
- }
- else ++unpackPtr;
- // Effect?
- if (control & 0x08)
- {
- *unpackPtr++ = *packPtr++;
- --packLeft;
- }
- else ++unpackPtr;
- // Effect parameter?
- if (control & 0x10)
- {
- *unpackPtr++ = *packPtr++;
- --packLeft;
- }
- else ++unpackPtr;
- }
- else
- {
- *unpackPtr++ = control; // Note
- *unpackPtr++ = *packPtr++; // Instrument
- *unpackPtr++ = *packPtr++; // Volume c.
- *unpackPtr++ = *packPtr++; // Effect
- *unpackPtr++ = *packPtr++; // Effect p.
- packLeft -= 4;
- }
- }
- }
- }
-
- // Load instruments
- mInstruments.resize(mXMHeader.mNumInstruments);
- memoryUse += mXMHeader.mNumInstruments * sizeof(XMInstrument);
-
- for (unsigned i = 0; i < mXMHeader.mNumInstruments; ++i)
- {
- XMInstrument* instrPtr = &mInstruments[i];
-
- // Read the part common to all instruments
- pos = source.getPosition();
- instrPtr->mHeaderSize = source.readUInt();
- source.read(instrPtr->mName, 22);
- instrPtr->mType = source.readUByte();
- instrPtr->mNumSamples = source.readUShort();
-
- if (instrPtr->mNumSamples)
- {
- instrPtr->mXMSamples.resize(instrPtr->mNumSamples);
- instrPtr->mSounds.resize(instrPtr->mNumSamples);
-
- int s;
-
- // There are samples; read the rest in
- instrPtr->mSoundHeaderSize = source.readUInt();
- source.read(&instrPtr->mSampleTable, 96);
- for (s = 0; s < 12; ++s)
- {
- instrPtr->mVolumeEnv[s].mX = source.readUShort();
- instrPtr->mVolumeEnv[s].mY = source.readUShort();
- }
- for (s = 0; s < 12; ++s)
- {
- instrPtr->mPanningEnv[s].mX = source.readUShort();
- instrPtr->mPanningEnv[s].mY = source.readUShort();
- }
- instrPtr->mVolumeEnvPoints = source.readUByte();
- instrPtr->mPanningEnvPoints = source.readUByte();
- instrPtr->mVolumeSustainPoint = source.readUByte();
- instrPtr->mVolumeLoopStart = source.readUByte();
- instrPtr->mVolumeLoopEnd = source.readUByte();
- instrPtr->mPanningSustainPoint = source.readUByte();
- instrPtr->mPanningLoopStart = source.readUByte();
- instrPtr->mPanningLoopEnd = source.readUByte();
- instrPtr->mVolumeEnvFlags = source.readUByte();
- instrPtr->mPanningEnvFlags = source.readUByte();
- instrPtr->mVibratoType = source.readUByte();
- instrPtr->mVibratoSweep = source.readUByte();
- instrPtr->mVibratoDepth = source.readUByte();
- instrPtr->mVibratoRate = source.readUByte();
- instrPtr->mFadeOut = source.readUShort();
- instrPtr->mReserved = source.readUShort();
-
- // Skip over extra data in instr. header
- source.seek(pos + instrPtr->mHeaderSize);
-
- // Precalculate envelopes
- if (instrPtr->mVolumeEnvFlags & ENV_ON)
- {
- for (s = 0; s < instrPtr->mVolumeEnvPoints; ++s)
- {
- // Paranoid check
- if (instrPtr->mVolumeEnv[s].mX > 324)
- instrPtr->mVolumeEnv[s].mX = 324;
- }
- for (s = 0; s < instrPtr->mVolumeEnvPoints - 1; ++s)
- {
- int x, y, dx, dy;
- y = instrPtr->mVolumeEnv[s].mY;
- dx = instrPtr->mVolumeEnv[s+1].mX - instrPtr->mVolumeEnv[s].mX;
- dy = instrPtr->mVolumeEnv[s+1].mY - instrPtr->mVolumeEnv[s].mY;
- if (dx)
- {
- for (x = 0; x < dx; ++x)
- {
- instrPtr->mVolumeEnvLookup[x + instrPtr->mVolumeEnv[s].mX] =
- y + dy * x / dx;
- }
- }
- if (s == instrPtr->mVolumeEnvPoints - 2)
- {
- for (x = instrPtr->mVolumeEnv[s+1].mX; x < 325; x++)
- instrPtr->mVolumeEnvLookup[x] = (unsigned char)instrPtr->mVolumeEnv[s+1].mY;
- }
- }
- instrPtr->mVolumeSustainPoint = instrPtr->mVolumeEnv[instrPtr->mVolumeSustainPoint].mX;
- instrPtr->mVolumeLoopStart = instrPtr->mVolumeEnv[instrPtr->mVolumeLoopStart].mX;
- instrPtr->mVolumeLoopEnd = instrPtr->mVolumeEnv[instrPtr->mVolumeLoopEnd].mY;
- // If zero length loop, must deactivate it
- if (instrPtr->mVolumeLoopStart == instrPtr->mVolumeLoopEnd)
- instrPtr->mVolumeEnvFlags &= ~ENV_LOOP;
- }
- if (instrPtr->mPanningEnvFlags & ENV_ON)
- {
- for (s = 0; s < instrPtr->mPanningEnvPoints; ++s)
- {
- // Paranoid check
- if (instrPtr->mPanningEnv[s].mX > 324)
- instrPtr->mPanningEnv[s].mX = 324;
- }
- for (s = 0; s < instrPtr->mPanningEnvPoints - 1; ++s)
- {
- int x, y, dx, dy;
- y = instrPtr->mPanningEnv[s].mY;
- dx = instrPtr->mPanningEnv[s+1].mX - instrPtr->mPanningEnv[s].mX;
- dy = instrPtr->mPanningEnv[s+1].mY - instrPtr->mPanningEnv[s].mY;
- if (dx)
- {
- for (x = 0; x < dx; ++x)
- {
- instrPtr->mPanningEnvLookup[x + instrPtr->mPanningEnv[s].mX] =
- y + dy * x / dx;
- }
- }
- if (s == instrPtr->mPanningEnvPoints - 2)
- {
- for (x = instrPtr->mPanningEnv[s+1].mX; x < 325; ++x)
- instrPtr->mPanningEnvLookup[x] = (unsigned char)instrPtr->mPanningEnv[s+1].mY;
- }
- }
- instrPtr->mPanningSustainPoint = instrPtr->mPanningEnv[instrPtr->mPanningSustainPoint].mX;
- instrPtr->mPanningLoopStart = instrPtr->mPanningEnv[instrPtr->mPanningLoopStart].mX;
- instrPtr->mPanningLoopEnd = instrPtr->mPanningEnv[instrPtr->mPanningLoopEnd].mX;
- // If zero length loop, must deactivate it
- if (instrPtr->mPanningLoopStart == instrPtr->mPanningLoopEnd)
- instrPtr->mPanningEnvFlags &= ~ENV_LOOP;
- }
-
- // Allocate xmsample & sample structures, but do not read any audio data yet
- for (s = 0; s < instrPtr->mNumSamples; ++s)
- {
- XMSample *xsp = &instrPtr->mXMSamples[s];
- SharedPtr<Sound> sp;
- unsigned reserve;
-
- // Read in sample header
- pos = source.getPosition();
- xsp->mLength = source.readUInt();
- xsp->mLoopStart = source.readUInt();
- xsp->mLoopLength = source.readUInt();
- xsp->mVolume = source.readUByte();
- xsp->mFineTune = source.readUByte();
- xsp->mSoundFlags = source.readUByte();
- xsp->mPanning = source.readUByte();
- xsp->mRelativeNote = source.readUByte();
- xsp->mReserved = source.readUByte();
- source.read(xsp->mName, 22);
-
- // Skip extra data in sample header
- source.seek(pos + instrPtr->mSoundHeaderSize);
-
- // If mLoopLength is zero, loop must be deactivated
- if (!xsp->mLoopLength)
- xsp->mSoundFlags &= ~(SMP_LOOP | SMP_PINGPONGLOOP);
-
- reserve = xsp->mLength;
-
- // There might be zero length samples
- if (reserve)
- {
- // Reserve sample
- if (xsp->mSoundFlags & SMP_PINGPONGLOOP) reserve += xsp->mLoopLength;
- sp = new Sound();
- sp->setSize(reserve);
- memoryUse += sp->getMemoryUse();
- }
-
- instrPtr->mSounds[s] = sp;
- }
-
- // Now load audio data
- for (s = 0; s < instrPtr->mNumSamples; ++s)
- {
- XMSample *xsp = &instrPtr->mXMSamples[s];
- Sound *sp = instrPtr->mSounds[s];
-
- if (sp)
- {
- // Read sample data (delta values)
- source.read(sp->getStart(), xsp->mLength);
-
- // Convert to normal signed data
- if (xsp->mSoundFlags & SMP_16BIT)
- {
- sp->setFormat(sp->getIntFrequency(), true, false);
-
- int cc = xsp->mLength >> 1;
- unsigned short old = 0;
- unsigned short *cptr = (unsigned short *)sp->getStart();
-
- while (cc--)
- {
- *cptr += old;
- old = *cptr++;
- }
- }
- else
- {
- int cc = xsp->mLength;
- signed char old = 0;
- signed char *cptr = sp->getStart();
-
- while (cc--)
- {
- *cptr += old;
- old = *cptr++;
- }
- }
-
- // "Unroll" pingpong-loop
- if (xsp->mSoundFlags & SMP_PINGPONGLOOP)
- {
- if (xsp->mSoundFlags & SMP_16BIT)
- {
- int uc = xsp->mLoopLength >> 1;
- short *source = (short *)(sp->getStart() + xsp->mLoopStart + xsp->mLoopLength - 2);
- short *dest = (short *)(sp->getStart() + xsp->mLoopStart + xsp->mLoopLength);
-
- while (uc--) *dest++ = *source--;
- }
- else
- {
- int uc = xsp->mLoopLength;
- signed char *source = sp->getStart() + xsp->mLoopStart + xsp->mLoopLength - 1;
- signed char *dest = sp->getStart() + xsp->mLoopStart + xsp->mLoopLength;
-
- while (uc--) *dest++ = *source--;
- }
- xsp->mLoopLength <<= 1;
- }
-
- // Set loop
- if (xsp->mSoundFlags & (SMP_LOOP|SMP_PINGPONGLOOP))
- sp->setLoop(xsp->mLoopStart, xsp->mLoopStart + xsp->mLoopLength);
- }
- }
- }
- else
- {
- // Header without samples; skip over extra if any
- source.seek(source.getPosition() + instrPtr->mHeaderSize - 29);
- }
- }
-
- setMemoryUse(memoryUse);
- mLoaded = true;
- }
- void XM::release()
- {
- stop();
-
- mLoaded = false;
-
- mTracks.clear();
- mPatterns.clear();
- mInstruments.clear();
- }
- void XM::play(unsigned position)
- {
- if (!mLoaded) return;
-
- stop();
-
- if (position >= mXMHeader.mSongLength)
- position = 0;
-
- mPos = position;
- mLine = 0;
- mTickCount = 0;
- mTickTempo = mXMHeader.mDefaultTickTempo;
- mGlobalVol = 64;
- mGlobalVolSpeedUp = 0;
- mGlobalVolSpeedDown = 0;
- mPatternDelay = 0;
- setBpmTempo(mXMHeader.mDefaultBpmTempo);
-
- setNumChannels(mXMHeader.mNumChannels);
-
- for (unsigned i = 0; i < mXMHeader.mNumChannels; ++i)
- {
- XMTrack* tptr = &mTracks[i];
- Channel* chptr = mChannels[i];
-
- memset(tptr, 0, sizeof(XMTrack));
- tptr->mInstr = &mInstruments[0];
- }
- if (mXMHeader.mUseLinear)
- {
- mLowPeriod = 7743;
- mHighPeriod = 64;
- }
- else
- {
- mLowPeriod = 29024;
- mHighPeriod = 28;
- }
-
- mPlaying = true;
- if (mAudio)
- mAudio->addSong(this);
- }
- void XM::updatePlayer()
- {
- XMPattern *pattPtr = &mPatterns[mXMHeader.mOrder[mPos]];
-
- // Set new notes or do something else?
- if ((!mTickCount) && (!mPatternDelay))
- {
- const XMNote* notePtr = (XMNote *)pattPtr->mData.getPtr();
-
- if (!notePtr) notePtr = &sEmptyNote;
- else notePtr += mXMHeader.mNumChannels * mLine;
-
- mPatternBreak = false;
- for (unsigned i = 0; i < mXMHeader.mNumChannels; ++i)
- {
- XMTrack* tptr = &mTracks[i];
- Channel* chptr = mChannels[i];
-
- tptr->mNewNote = 0;
- tptr->mRetrigCount = 0;
-
- // Get note (if any)
- if (notePtr->mNote)
- {
- tptr->mNote = notePtr->mNote - 1;
- tptr->mNewNote = 1;
- }
-
- // Get effect & data
- tptr->mVolEffect = notePtr->mVolEffect;
- tptr->mEffect = notePtr->mEffect;
- tptr->mEffectData = notePtr->mEffectData;
- tptr->mNybble1 = notePtr->mEffectData >> 4;
- tptr->mNybble2 = notePtr->mEffectData & 0xf;
- tptr->mNewInstrument = notePtr->mInstrument;
-
- // Set sampleoffset here
- if (tptr->mEffect == 0x9)
- {
- if (tptr->mEffectData)
- tptr->mSoundOffset = tptr->mEffectData;
- }
-
- // Start new note if there is one
- if ((tptr->mEffect != 0xe) || (tptr->mNybble1 != 0xd) || (tptr->mNybble2 == 0))
- {
- if (tptr->mNewNote) startNewNote(tptr, chptr);
- if (tptr->mNewInstrument) changeInstrument(tptr);
- }
-
- // Reset period if not vibrato or toneportamento
- if (((tptr->mEffect < 0x3) || (tptr->mEffect > 0x6)) && (tptr->mVolEffect != 0xb) && (tptr->mVolEffect != 0xf))
- tptr->mPeriod = tptr->mBasePeriod;
-
- // Reset volume if not tremolo / tremor
- if ((tptr->mEffect != 0x7) && (tptr->mEffect != 0x1d))
- tptr->mVolume = tptr->mNoteVolume;
-
- // Now check effects: volume column done first
- switch (tptr->mVolEffect >> 4)
- {
- case 0x0:
- break;
-
- // Set volume
- case 0x1:
- case 0x2:
- case 0x3:
- case 0x4:
- case 0x5:
- // Applies only if there isn't notedelay
- if ((tptr->mEffect != 0xe) || (tptr->mNybble1 != 0xd) || (tptr->mNybble2 == 0))
- {
- tptr->mNoteVolume = tptr->mVolEffect - 0x10;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- }
- break;
-
- // Fine volslide down
- case 0x8:
- tptr->mNoteVolume -= tptr->mVolEffect & 0xf;
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- tptr->mVolume = tptr->mNoteVolume;
- break;
-
- // Fine volslide up
- case 0x9:
- tptr->mNoteVolume += tptr->mVolEffect & 0xf;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- break;
-
- // Set vibrato speed
- case 0xa:
- if (tptr->mVolEffect & 0xf)
- tptr->mVibratoSpeed = tptr->mVolEffect & 0xf;
- break;
-
- // Vibrato
- case 0xb:
- if (tptr->mVolEffect & 0xf)
- tptr->mVibratoDepth = tptr->mVolEffect & 0xf;
- break;
-
- // Set panning
- case 0xc:
- // Applies only if there isn't notedelay
- if ((tptr->mEffect != 0xe) || (tptr->mNybble1 != 0xd) || (tptr->mNybble2 == 0))
- tptr->mNotePanning = (tptr->mVolEffect & 0xf) << 4 | (tptr->mVolEffect & 0xf);
- break;
-
- // Toneportamento
- case 0xf:
- if (tptr->mVolEffect & 0xf)
- tptr->mTonePortaSpeed = (tptr->mVolEffect & 0xf) << 4;
- break;
- }
-
- // Then the regular effects
- switch (tptr->mEffect)
- {
- case 0x0:
- break;
-
- // Set portamento speed up
- case 0x1:
- if (tptr->mEffectData) tptr->mPortaSpeedUp = tptr->mEffectData;
- break;
-
- // Set portamento speed down
- case 0x2:
- if (tptr->mEffectData) tptr->mPortaSpeedDown = tptr->mEffectData;
- break;
-
- // Set TP. speed
- case 0x3:
- if (tptr->mEffectData) tptr->mTonePortaSpeed = tptr->mEffectData;
- break;
-
- // Set vibrato
- case 0x4:
- if (tptr->mNybble1) tptr->mVibratoSpeed = tptr->mNybble1;
- if (tptr->mNybble2) tptr->mVibratoDepth = tptr->mNybble2;
- break;
-
- // Set tremolo
- case 0x7:
- if (tptr->mNybble1) tptr->mTremoloSpeed = tptr->mNybble1;
- if (tptr->mNybble2) tptr->mTremoloDepth = tptr->mNybble2;
- break;
-
- // Set panning
- case 0x8:
- tptr->mNotePanning = tptr->mEffectData;
- break;
-
- // ´Set volume slide speed
- case 0x5:
- case 0x6:
- case 0xa:
- if (tptr->mEffectData)
- {
- tptr->mVolumeSpeedUp = tptr->mNybble1;
- tptr->mVolumeSpeedDown = tptr->mNybble2;
- }
- break;
-
- // Pos. jump
- case 0xb:
- mLine = pattPtr->mRows - 1;
- mPos = tptr->mEffectData - 1;
- break;
-
- // Set volume
- case 0xc:
- tptr->mNoteVolume = tptr->mEffectData;
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- break;
-
- // Pattern break
- case 0xd:
- if (!mPatternBreak)
- {
- mPatternBreak = true;
- mLine = tptr->mNybble1 * 10 + tptr->mNybble2 - 1;
- mPos++;
- }
- break;
-
- // Extended command
- case 0xe:
- extendedCommand(tptr, chptr);
- break;
-
- // Set tempo
- case 0xf:
- if (tptr->mEffectData < 32) mTickTempo = tptr->mEffectData;
- else setBpmTempo(tptr->mEffectData);
- break;
-
- // Global volume
- case 0x10:
- mGlobalVol = tptr->mEffectData;
- if (mGlobalVol > 64) mGlobalVol = 64;
- break;
-
- // Global volume slide
- case 0x11:
- if (tptr->mEffectData)
- {
- mGlobalVolSpeedUp = tptr->mNybble1;
- mGlobalVolSpeedDown = tptr->mNybble2;
- }
- break;
-
- // Keyoff
- case 0x14:
- tptr->mKeyOn = false;
- if (!(tptr->mInstr->mVolumeEnvFlags & ENV_ON))
- {
- tptr->mNoteVolume = 0;
- tptr->mVolume = 0;
- }
- break;
-
- // Set envpos
- case 0x15:
- tptr->mVolumeEnvPos = tptr->mEffectData;
- tptr->mPanningEnvPos = tptr->mEffectData;
- break;
-
- // Panning slide
- case 0x19:
- if (tptr->mEffectData)
- {
- tptr->mPanningSpeedRight = tptr->mNybble1;
- tptr->mPanningSpeedLeft = tptr->mNybble2;
- }
- break;
-
- // Multi retrig
- case 0x1b:
- if (tptr->mNybble1) tptr->mRetrigVolChange = tptr->mNybble1;
- if (tptr->mNybble2) tptr->mRetrigInterval = tptr->mNybble2;
- if (tptr->mMultiRetrigCount >= tptr->mRetrigInterval)
- {
- startNewNote(tptr, chptr);
- tptr->mMultiRetrigCount = 0;
- if (!sRetrigMulTable[tptr->mRetrigVolChange])
- {
- tptr->mNoteVolume += sRetrigAddTable[tptr->mRetrigVolChange];
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- }
- else
- {
- tptr->mNoteVolume = (tptr->mNoteVolume * sRetrigMulTable[tptr->mRetrigVolChange]) >> 4;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- }
- }
- tptr->mMultiRetrigCount++;
- break;
-
- // Tremor
- case 0x1d:
- if (tptr->mEffectData)
- {
- tptr->mTremorOnTime = tptr->mNybble1;
- tptr->mTremorOffTime = tptr->mNybble2;
- }
- break;
-
- // Extra fine portamento
- case 0x21:
- switch (tptr->mNybble1)
- {
- case 1:
- if (tptr->mNybble2) tptr->mPortaSpeedUp = tptr->mNybble2;
- tptr->mBasePeriod -= tptr->mPortaSpeedUp;
- if (tptr->mBasePeriod < mHighPeriod) tptr->mBasePeriod = mHighPeriod;
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- case 2:
- if (tptr->mNybble2) tptr->mPortaSpeedDown = tptr->mNybble2;
- tptr->mBasePeriod += tptr->mPortaSpeedDown;
- if (tptr->mBasePeriod > mLowPeriod) tptr->mBasePeriod = mLowPeriod;
- tptr->mPeriod = tptr->mBasePeriod;
- break;
- }
- break;
- }
- if (notePtr != &sEmptyNote) notePtr++;
- }
- }
- if (mTickCount)
- {
- // If tick isn't 0, update "continuous" effects
- for (unsigned i = 0; i < mXMHeader.mNumChannels; ++i)
- {
- XMTrack* tptr = &mTracks[i];
- Channel* chptr = mChannels[i];
-
- switch (tptr->mVolEffect >> 4)
- {
- case 0x0:
- break;
-
- // Volslide down
- case 0x6:
- tptr->mNoteVolume -= tptr->mVolEffect & 0xf;
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- tptr->mVolume = tptr->mNoteVolume;
- break;
-
- // Volslide up
- case 0x7:
- tptr->mNoteVolume += tptr->mVolEffect & 0xf;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- break;
-
- // Vibrato
- case 0xb:
- tptr->mVibratoPhase += tptr->mVibratoSpeed * 4;
- tptr->mPeriod = tptr->mBasePeriod + ((Song::sVibratoTable[tptr->mVibratoType & 3][tptr->mVibratoPhase] * tptr->mVibratoDepth) >> 3);
- if (tptr->mPeriod < mHighPeriod) tptr->mPeriod = mHighPeriod;
- if (tptr->mPeriod > mLowPeriod) tptr->mPeriod = mLowPeriod;
- break;
-
- // Panslide left
- case 0xd:
- {
- int newPan = tptr->mNotePanning;
- newPan -= tptr->mVolEffect & 0xf;
- if (newPan < 0) newPan = 0;
- tptr->mNotePanning = newPan;
- }
- break;
-
- // Panslide right
- case 0xe:
- {
- int newPan = tptr->mNotePanning;
- newPan += tptr->mVolEffect & 0xf;
- if (newPan > 255) newPan = 255;
- tptr->mNotePanning = newPan;
- }
- break;
-
- // Toneportamento
- case 0xf:
- tonePortamento(tptr, chptr);
- break;
- }
-
- // Regular effects
- switch (tptr->mEffect)
- {
- // Arpeggio
- case 0x0:
- if (tptr->mEffectData)
- {
- char phase = mTickCount % 3;
- switch (phase)
- {
- case 0:
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- case 1:
- if (mXMHeader.mUseLinear) tptr->mPeriod = tptr->mBasePeriod - tptr->mNybble1 * 64;
- else tptr->mPeriod = getAmigaPeriod(tptr->mRealNote + tptr->mNybble1, tptr->mFineTune);
- if (tptr->mPeriod < mHighPeriod) tptr->mPeriod = mHighPeriod;
- break;
-
- case 2:
- if (mXMHeader.mUseLinear) tptr->mPeriod = tptr->mBasePeriod - tptr->mNybble2 * 64;
- else tptr->mPeriod = getAmigaPeriod(tptr->mRealNote + tptr->mNybble2, tptr->mFineTune);
- if (tptr->mPeriod < mHighPeriod) tptr->mPeriod = mHighPeriod;
- break;
- }
- }
- break;
-
- // Portamento up
- case 0x1:
- tptr->mBasePeriod -= tptr->mPortaSpeedUp * 4;
- if (tptr->mBasePeriod < mHighPeriod) tptr->mBasePeriod = mHighPeriod;
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- // Portamento down
- case 0x2:
- tptr->mBasePeriod += tptr->mPortaSpeedDown * 4;
- if (tptr->mBasePeriod > mLowPeriod) tptr->mBasePeriod = mLowPeriod;
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- // Toneportamento
- case 0x3:
- tonePortamento(tptr, chptr);
- break;
-
- // Vibrato
- case 0x4:
- vibrato(tptr, chptr);
- break;
-
- // Toneportamento + volslide
- case 0x5:
- tonePortamento(tptr, chptr);
- volumeSlide(tptr, chptr);
- break;
-
- // Vibrato + volslide
- case 0x6:
- vibrato(tptr, chptr);
- volumeSlide(tptr, chptr);
- break;
-
- // Tremolo
- case 0x7:
- tptr->mTremoloPhase += tptr->mTremoloSpeed * 4;
- tptr->mVolume = tptr->mNoteVolume + ((Song::sVibratoTable[tptr->mTremoloType & 3][tptr->mTremoloPhase] * tptr->mTremoloDepth) >> 4);
- if (tptr->mVolume < 0) tptr->mVolume = 0;
- if (tptr->mVolume > 64) tptr->mVolume = 64;
- break;
-
- // Volume slide
- case 0xa:
- volumeSlide(tptr, chptr);
- break;
-
- // Extended command
- case 0xe:
- extendedCommand(tptr, chptr);
- break;
-
- // Global volume slide
- case 0x11:
- if (mGlobalVolSpeedUp)
- {
- mGlobalVol += mGlobalVolSpeedUp;
- if (mGlobalVol > 64) mGlobalVol = 64;
- }
- else
- {
- mGlobalVol -= mGlobalVolSpeedDown;
- if (mGlobalVol < 0) mGlobalVol = 0;
- }
- break;
-
- // Panning slide
- case 0x19:
- {
- int newPan = tptr->mNotePanning;
-
- newPan += tptr->mPanningSpeedRight;
- if (newPan < 0) newPan = 0;
- newPan -= tptr->mPanningSpeedLeft;
- if (newPan > 255) newPan = 255;
- tptr->mNotePanning = newPan;
- }
- break;
-
- // Multi retrig
- case 0x1b:
- if (tptr->mMultiRetrigCount >= tptr->mRetrigInterval)
- {
- startNewNote(tptr, chptr);
- tptr->mMultiRetrigCount = 0;
- if (!sRetrigMulTable[tptr->mRetrigVolChange])
- {
- tptr->mNoteVolume += sRetrigAddTable[tptr->mRetrigVolChange];
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- }
- else
- {
- tptr->mNoteVolume = (tptr->mNoteVolume * sRetrigMulTable[tptr->mRetrigVolChange]) >> 4;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- tptr->mVolume = tptr->mNoteVolume;
- }
- }
- tptr->mMultiRetrigCount++;
- break;
-
- // Tremor
- case 0x1d:
- if (!tptr->mTremorCount)
- {
- tptr->mTremorStatus ^= 1;
- if (tptr->mTremorStatus) tptr->mTremorCount = tptr->mTremorOnTime + 1;
- else tptr->mTremorCount = tptr->mTremorOffTime + 1;
- }
- if (tptr->mTremorStatus) tptr->mVolume = tptr->mNoteVolume;
- else tptr->mVolume = 0;
- tptr->mTremorCount--;
- break;
- }
- chptr++;
- tptr++;
- }
- }
- // Update envelopes and set the frequency, volume & panning of the channel
- for (unsigned i = 0; i < mXMHeader.mNumChannels; ++i)
- {
- XMTrack* tptr = &mTracks[i];
- Channel* chptr = mChannels[i];
- XMInstrument *instrPtr = tptr->mInstr;
- short finalPeriod = tptr->mPeriod;
-
- // Update fadeout (must be done before before calculating the final volume)
- if (!tptr->mKeyOn)
- {
- tptr->mFadeOutValue -= instrPtr->mFadeOut;
- if (tptr->mFadeOutValue < 0) tptr->mFadeOutValue = 0;
- }
-
- // Calculate final channel values
- int finalVol;
- if (instrPtr->mVolumeEnvFlags & ENV_ON)
- finalVol = (tptr->mVolume * mGlobalVol * instrPtr->mVolumeEnvLookup[tptr->mVolumeEnvPos] * (tptr->mFadeOutValue >> 9)) >> 18;
- else
- finalVol = (tptr->mVolume * mGlobalVol * (tptr->mFadeOutValue >> 9)) >> 12;
- int finalPan;
- if (instrPtr->mPanningEnvFlags & ENV_ON)
- finalPan = tptr->mNotePanning + (instrPtr->mPanningEnvLookup[tptr->mPanningEnvPos] - 32) * (128 - abs(tptr->mNotePanning - 128)) / 32;
- else
- finalPan = tptr->mNotePanning;
-
- chptr->setIntVolume(finalVol);
- chptr->setIntPanning(finalPan);
-
- // Update instrument vibrato
- if ((instrPtr->mVibratoDepth) && (instrPtr->mVibratoRate))
- {
- if (instrPtr->mVibratoSweep)
- {
- if (tptr->mKeyOn)
- {
- tptr->mInstrVibratoDepth += (instrPtr->mVibratoDepth << 8) / instrPtr->mVibratoSweep;
- if (tptr->mInstrVibratoDepth > (instrPtr->mVibratoDepth << 8)) tptr->mInstrVibratoDepth = instrPtr->mVibratoDepth << 8;
- }
- }
- else tptr->mInstrVibratoDepth = instrPtr->mVibratoDepth << 8;
- tptr->mInstrVibratoPhase += instrPtr->mVibratoRate;
- finalPeriod += (Song::sVibratoTable[instrPtr->mVibratoType & 3][tptr->mInstrVibratoPhase] * tptr->mInstrVibratoDepth) >> 14;
- }
- if (finalPeriod < (mHighPeriod - 15)) finalPeriod = mHighPeriod - 15;
- if (finalPeriod > (mLowPeriod + 15)) finalPeriod = mLowPeriod + 15;
-
- if (mXMHeader.mUseLinear)
- chptr->setIntFrequency(sLinearFreqTable[finalPeriod % 768] >> (finalPeriod / 768));
- else
- chptr->setIntFrequency(14317456 / finalPeriod);
-
- // Update envelopes
- if ((instrPtr->mVolumeEnvFlags & ENV_ON) && ((!(instrPtr->mVolumeEnvFlags & ENV_SUSTAIN)) || (!tptr->mKeyOn) || (tptr->mVolumeEnvPos != instrPtr->mVolumeSustainPoint)))
- {
- tptr->mVolumeEnvPos++;
- if (tptr->mVolumeEnvPos > 324) tptr->mVolumeEnvPos = 324;
- if (instrPtr->mVolumeEnvFlags & ENV_LOOP)
- {
- if (tptr->mVolumeEnvPos >= instrPtr->mVolumeLoopEnd)
- tptr->mVolumeEnvPos = instrPtr->mVolumeLoopStart;
- }
- }
- if ((instrPtr->mPanningEnvFlags & ENV_ON) && ((!(instrPtr->mPanningEnvFlags & ENV_SUSTAIN)) || (!tptr->mKeyOn) || (tptr->mPanningEnvPos != instrPtr->mPanningSustainPoint)))
- {
- tptr->mPanningEnvPos++;
- if (tptr->mPanningEnvPos > 324) tptr->mPanningEnvPos = 324;
- if (instrPtr->mPanningEnvFlags & ENV_LOOP)
- {
- if (tptr->mPanningEnvPos >= instrPtr->mPanningLoopEnd)
- tptr->mPanningEnvPos = instrPtr->mPanningLoopStart;
- }
- }
- }
-
- // Advance song
- if (mTickTempo)
- {
- mTickCount++;
- if (mTickCount >= mTickTempo)
- {
- mTickCount = 0;
- if (mPatternDelay)
- mPatternDelay--;
- if (!mPatternDelay)
- {
- mLine++;
- if (mLine >= pattPtr->mRows)
- {
- mLine = 0;
- mPos++;
- }
- if (mPos >= mXMHeader.mSongLength)
- mPos = mXMHeader.mRestartPos;
- }
- }
- }
- }
- void XM::startNewNote(XMTrack* tptr, Channel* chptr)
- {
- if (tptr->mNewInstrument)
- tptr->mInstrument = tptr->mNewInstrument - 1;
-
- // Handle keyoff
- if (tptr->mNote == KEYOFF - 1)
- {
- tptr->mKeyOn = false;
- if (!(tptr->mInstr->mVolumeEnvFlags & ENV_ON))
- {
- tptr->mNoteVolume = 0;
- tptr->mVolume = 0;
- }
- return;
- }
-
- // Now get instrptr & sampleptr, but don't change them if using toneportamento
- if ((tptr->mEffect == 0x3) || (tptr->mEffect == 0x5) || ((tptr->mVolEffect >> 4) == 0xf))
- tptr->mTonePortamento = true;
- else
- {
- tptr->mTonePortamento = false;
- if (tptr->mInstrument < mXMHeader.mNumInstruments)
- tptr->mInstr = &mInstruments[tptr->mInstrument];
-
- tptr->mSoundNumber = tptr->mInstr->mSampleTable[tptr->mNote];
- tptr->mXMSample = &tptr->mInstr->mXMSamples[tptr->mSoundNumber];
- tptr->mSound = tptr->mInstr->mSounds[tptr->mSoundNumber];
- }
-
- // Don't go further if sample doesn't exist
- if ((tptr->mXMSample) && (tptr->mSound))
- {
- tptr->mFineTune = tptr->mXMSample->mFineTune;
- tptr->mMultiRetrigCount = 1;
- if (!(tptr->mVibratoType & 4)) tptr->mVibratoPhase = 0;
- if (!(tptr->mTremoloType & 4)) tptr->mTremoloPhase = 0;
- tptr->mTremorCount = 0;
- tptr->mTremorStatus = 0;
- tptr->mRealNote = tptr->mNote + tptr->mXMSample->mRelativeNote;
- if (tptr->mRealNote < 0) tptr->mRealNote = 0;
- if (tptr->mRealNote > 118) tptr->mRealNote = 118;
- if (tptr->mTonePortamento)
- {
- // Toneportamento
- if (mXMHeader.mUseLinear) tptr->mTargetPeriod = 7680 - tptr->mRealNote * 64 - tptr->mFineTune / 2;
- else tptr->mTargetPeriod = getAmigaPeriod(tptr->mRealNote, tptr->mFineTune);
- }
- else
- {
- // Normal note start
- if (mXMHeader.mUseLinear) tptr->mBasePeriod = 7680 - tptr->mRealNote * 64 - tptr->mFineTune / 2;
- else tptr->mBasePeriod = getAmigaPeriod(tptr->mRealNote, tptr->mFineTune);
- tptr->mPeriod = tptr->mBasePeriod;
- chptr->playLockless(tptr->mSound);
-
- if (tptr->mEffect == 0x9)
- {
- signed char *newPos;
- if (tptr->mSound->isSixteenBit())
- newPos = tptr->mSound->getStart() + (tptr->mSoundOffset << 9);
- else
- newPos = tptr->mSound->getStart() + (tptr->mSoundOffset << 8);
-
- if (newPos >= tptr->mSound->getEnd())
- chptr->stopLockless();
- else
- chptr->setPlayPositionLockless(newPos);
- }
- }
- }
- }
- void XM::tonePortamento(XMTrack* tptr, Channel* chptr)
- {
- if (tptr->mTonePortamento)
- {
- if (tptr->mBasePeriod < tptr->mTargetPeriod)
- {
- tptr->mBasePeriod += tptr->mTonePortaSpeed * 4;
- if (tptr->mBasePeriod >= tptr->mTargetPeriod)
- {
- tptr->mBasePeriod = tptr->mTargetPeriod;
- tptr->mTonePortamento = false;
- }
- }
- if (tptr->mBasePeriod > tptr->mTargetPeriod)
- {
- tptr->mBasePeriod -= tptr->mTonePortaSpeed * 4;
- if (tptr->mBasePeriod <= tptr->mTargetPeriod)
- {
- tptr->mBasePeriod = tptr->mTargetPeriod;
- tptr->mTonePortamento = false;
- }
- }
- tptr->mPeriod = tptr->mBasePeriod;
- if (tptr->mGlissando)
- {
- if (mXMHeader.mUseLinear)
- {
- tptr->mPeriod += tptr->mFineTune / 2;
- tptr->mPeriod += 32;
- tptr->mPeriod &= 0xffc0;
- tptr->mPeriod -= tptr->mFineTune / 2;
- }
- else
- {
- int offset = M_MAX_INT;
- int sc;
- short bestperiod = 0;
-
- for (sc = 0; sc <= 118; sc++)
- {
- int newoffset = abs((int)tptr->mPeriod - (int)getAmigaPeriod(sc, tptr->mFineTune));
-
- if (newoffset < offset)
- {
- bestperiod = getAmigaPeriod(sc, tptr->mFineTune);
- offset = newoffset;
- }
- }
- tptr->mPeriod = bestperiod;
- }
- }
- }
- }
- void XM::vibrato(XMTrack* tptr, Channel* chptr)
- {
- tptr->mVibratoPhase += tptr->mVibratoSpeed * 4;
- tptr->mPeriod = tptr->mBasePeriod + ((Song::sVibratoTable[tptr->mVibratoType & 3][tptr->mVibratoPhase] * tptr->mVibratoDepth) >> 3);
- if (tptr->mPeriod < mHighPeriod) tptr->mPeriod = mHighPeriod;
- if (tptr->mPeriod > mLowPeriod) tptr->mPeriod = mLowPeriod;
- }
- void XM::volumeSlide(XMTrack* tptr, Channel* chptr)
- {
- if (tptr->mVolumeSpeedUp)
- {
- tptr->mNoteVolume += tptr->mVolumeSpeedUp;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- }
- else
- {
- tptr->mNoteVolume -= tptr->mVolumeSpeedDown;
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- }
- tptr->mVolume = tptr->mNoteVolume;
- }
- void XM::extendedCommand(XMTrack* tptr, Channel* chptr)
- {
- switch(tptr->mNybble1)
- {
- // Fine porta up
- case 0x1:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mPortaSpeedUp = tptr->mNybble2;
- tptr->mBasePeriod -= tptr->mPortaSpeedUp * 4;
- if (tptr->mBasePeriod < mHighPeriod) tptr->mBasePeriod = mHighPeriod;
- }
- break;
-
- // Fine porta down
- case 0x2:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mPortaSpeedDown = tptr->mNybble2;
- tptr->mBasePeriod += tptr->mPortaSpeedDown * 4;
- if (tptr->mBasePeriod > mLowPeriod) tptr->mBasePeriod = mLowPeriod;
- }
- break;
-
- // Set glissando
- case 0x3:
- if (!mTickCount) tptr->mGlissando = tptr->mNybble2;
- break;
-
- // Set vibrato waveform
- case 0x4:
- if (!mTickCount)
- {
- tptr->mVibratoType = Song::sVibratoTypeTable[tptr->mNybble2 & 3];
- tptr->mVibratoType |= tptr->mNybble2 & 4;
- }
- break;
-
- // Set finetune
- case 0x5:
- if ((!mTickCount) && (tptr->mNewNote))
- {
- tptr->mFineTune = (tptr->mNybble2 << 4) - 128;
- if (mXMHeader.mUseLinear) tptr->mBasePeriod = 7680 - tptr->mRealNote * 64 - tptr->mFineTune / 2;
- else tptr->mBasePeriod = getAmigaPeriod(tptr->mRealNote, tptr->mFineTune);
- tptr->mPeriod = tptr->mBasePeriod;
- }
- break;
-
- // Patternloop
- case 0x6:
- if (!mTickCount)
- {
- if (!tptr->mNybble2)
- tptr->mPatternLoopLine = mLine;
- else
- {
- if (!tptr->mPatternLoopCount)
- {
- tptr->mPatternLoopCount = tptr->mNybble2;
- mLine = tptr->mPatternLoopLine - 1;
- }
- else
- {
- tptr->mPatternLoopCount--;
- if (tptr->mPatternLoopCount) mLine = tptr->mPatternLoopLine - 1;
- }
- }
- }
- break;
-
- // Set tremolo waveform
- case 0x7:
- if (!mTickCount)
- {
- tptr->mTremoloType = Song::sVibratoTypeTable[tptr->mNybble2 & 3];
- tptr->mTremoloType |= tptr->mNybble2 & 4;
- }
- break;
-
- // Retrig
- case 0x9:
- if (tptr->mNybble2)
- {
- if (tptr->mRetrigCount >= tptr->mNybble2)
- {
- tptr->mRetrigCount = 0;
- // Don't retrig on tick 0
- if (mTickCount)
- {
- startNewNote(tptr, chptr);
- tptr->mKeyOn = true;
- tptr->mFadeOutValue = 32768;
- tptr->mVolumeEnvPos = 0;
- tptr->mPanningEnvPos = 0;
- tptr->mInstrVibratoPhase = 0;
- tptr->mInstrVibratoDepth = 0;
- }
- }
- }
- else
- {
- // Special case e90: start the note at tick 0 but don't restart envelope
- if (!mTickCount)
- {
- startNewNote(tptr, chptr);
- }
- }
- tptr->mRetrigCount++;
- break;
-
- // Notedelay
- case 0xd:
- // Don't start on tick 0
- if (!mTickCount) break;
- if (mTickCount == tptr->mNybble2)
- {
- startNewNote(tptr, chptr);
- if (tptr->mNewInstrument)
- changeInstrument(tptr);
- else
- {
- tptr->mKeyOn = true;
- tptr->mFadeOutValue = 32768;
- tptr->mVolumeEnvPos = 0;
- tptr->mPanningEnvPos = 0;
- tptr->mInstrVibratoPhase = 0;
- tptr->mInstrVibratoDepth = 0;
- }
- if ((tptr->mVolEffect >= 0x10) && (tptr->mVolEffect <= 0x50))
- {
- tptr->mNoteVolume = tptr->mVolEffect - 0x10;
- tptr->mVolume = tptr->mNoteVolume;
- }
- if ((tptr->mVolEffect >> 4) == 0xc)
- {
- tptr->mNotePanning = (tptr->mVolEffect & 0xf) << 4 | (tptr->mVolEffect & 0xf);
- }
- }
- break;
-
- // Cut note
- case 0xc:
- if (mTickCount == tptr->mNybble2) tptr->mNoteVolume = 0;
- break;
-
- // Fine volslide up
- case 0xa:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mVolumeSpeedUp = tptr->mNybble2;
- tptr->mNoteVolume += tptr->mVolumeSpeedUp;
- if (tptr->mNoteVolume > 64) tptr->mNoteVolume = 64;
- }
- break;
-
- // Fine volslide down
- case 0xb:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mVolumeSpeedDown = tptr->mNybble2;
- tptr->mNoteVolume -= tptr->mVolumeSpeedDown;
- if (tptr->mNoteVolume < 0) tptr->mNoteVolume = 0;
- }
- break;
-
- // Patterndelay
- case 0xe:
- if (!mTickCount)
- {
- mPatternDelay = tptr->mNybble2 + 1;
- }
- break;
- }
- }
- void XM::changeInstrument(XMTrack* tptr)
- {
- tptr->mInstrument = tptr->mNewInstrument - 1;
- if (tptr->mXMSample)
- {
- tptr->mNotePanning = tptr->mXMSample->mPanning;
- tptr->mNoteVolume = tptr->mXMSample->mVolume;
- tptr->mVolume = tptr->mNoteVolume;
- }
-
- // Must not restart envelopes if there's a keyoff just in that place
- if ((!tptr->mNewNote) || (tptr->mNote != KEYOFF - 1))
- {
- tptr->mKeyOn = true;
- tptr->mFadeOutValue = 32768;
- tptr->mVolumeEnvPos = 0;
- tptr->mPanningEnvPos = 0;
- tptr->mInstrVibratoPhase = 0;
- tptr->mInstrVibratoDepth = 0;
- }
- }
- unsigned XM::getAmigaPeriod(int mNote, int fineTune)
- {
- int noteOffset = (mNote % 12) << 3;
- if (fineTune >= 0)
- {
- int roughFineTune = fineTune >> 4;
- int fineFineTune = fineTune & 15;
- return ((sAmigaFreqTable[8 + noteOffset + roughFineTune] * (16 - fineFineTune) +
- sAmigaFreqTable[9 + noteOffset + roughFineTune] * fineFineTune)
- * 2) >> (mNote / 12);
- }
- else
- {
- int roughFineTune = (fineTune - 15) >> 4;
- int fineFineTune = fineTune & 15;
- return ((sAmigaFreqTable[8 + noteOffset + roughFineTune] * (16 - fineFineTune) +
- sAmigaFreqTable[9 + noteOffset + roughFineTune] * fineFineTune)
- * 2) >> (mNote / 12);
- }
- }
|