| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- //
- // 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 "Mod.h"
- #include "Profiler.h"
- #include "Sound.h"
- #include <cstring>
- #include "DebugNew.h"
- static const int AMIGA_CLOCK = 3579545;
- static const int MOD_INSTRUMENTS = 31;
- static const int MOD_MAXLENGTH = 128;
- static const int MOD_MAXCHANNELS = 32;
- static const int MOD_INFOBLOCK = 1084;
- static const int MOD_NAMEOFFSET = 0;
- static const int MOD_INSTROFFSET = 20;
- static const int MOD_LENGTHOFFSET = 950;
- static const int MOD_ORDEROFFSET = 952;
- static const int MOD_IDENTOFFSET = 1080;
- const ModIdent Mod::sIdent[] =
- {
- {"2CHN", 2},
- {"M.K.", 4},
- {"M!K!", 4},
- {"4CHN", 4},
- {"6CHN", 6},
- {"8CHN", 8},
- {"10CH", 10},
- {"12CH", 12},
- {"14CH", 14},
- {"16CH", 16},
- {"18CH", 18},
- {"20CH", 20},
- {"22CH", 22},
- {"24CH", 24},
- {"26CH", 26},
- {"28CH", 28},
- {"30CH", 30},
- {"32CH", 32}
- };
- const unsigned short Mod::sPeriodTable[16][12] =
- {
- {6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624},
- {6800, 6416, 6056, 5720, 5392, 5096, 4808, 4536, 4280, 4040, 3816, 3600},
- {6752, 6368, 6016, 5672, 5360, 5056, 4776, 4504, 4256, 4016, 3792, 3576},
- {6704, 6328, 5968, 5632, 5320, 5024, 4736, 4472, 4224, 3984, 3760, 3552},
- {6656, 6280, 5928, 5592, 5280, 4984, 4704, 4440, 4192, 3960, 3736, 3528},
- {6608, 6232, 5888, 5552, 5240, 4952, 4672, 4408, 4160, 3928, 3704, 3496},
- {6560, 6192, 5840, 5512, 5208, 4912, 4640, 4376, 4128, 3896, 3680, 3472},
- {6512, 6144, 5800, 5472, 5168, 4880, 4600, 4344, 4104, 3872, 3656, 3448},
- {7256, 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4032, 3840},
- {7200, 6800, 6416, 6056, 5720, 5400, 5088, 4808, 4536, 4280, 4040, 3816},
- {7152, 6752, 6368, 6016, 5672, 5360, 5056, 4776, 4504, 4256, 4016, 3792},
- {7096, 6704, 6328, 5968, 5632, 5320, 5024, 4736, 4472, 4224, 3984, 3760},
- {7048, 6656, 6280, 5928, 5592, 5280, 4984, 4704, 4440, 4192, 3952, 3736},
- {7000, 6608, 6232, 5888, 5552, 5240, 4952, 4672, 4408, 4160, 3928, 3704},
- {6944, 6560, 6192, 5840, 5512, 5208, 4912, 4640, 4376, 4128, 3896, 3680},
- {6896, 6512, 6144, 5800, 5472, 5168, 4880, 4600, 4344, 4104, 3872, 3656}
- };
- Mod::Mod(Audio* audio, const std::string& name) :
- Song(audio, name),
- mPos(0)
- {
- }
- Mod::~Mod()
- {
- release();
- }
- void Mod::load(Deserializer& source, ResourceCache* cache)
- {
- PROFILE(Mod_Load);
-
- release();
-
- unsigned memoryUse = 0;
-
- // Load info
- mInfo = new unsigned char[MOD_INFOBLOCK];
- source.read(mInfo.getPtr(), MOD_INFOBLOCK);
- mInfo[20] = 0;
- memoryUse += MOD_INFOBLOCK;
-
- mNumChannels = 0;
- for (unsigned i = 0; i < 18; ++i)
- {
- if (!memcmp(sIdent[i].mString.c_str(), &mInfo[MOD_IDENTOFFSET], 4))
- mNumChannels = sIdent[i].mChannels;
- }
-
- if (!mNumChannels)
- EXCEPTION("Could not determine mod format from " + source.getName());
-
- // Create tracks
- mTracks.resize(mNumChannels);
-
- mPatternLength = mNumChannels * 256;
- mLength = mInfo[MOD_LENGTHOFFSET];
- unsigned char* order = &mInfo[MOD_ORDEROFFSET];
-
- mNumPatterns = 0;
- for (unsigned i = 0; i < MOD_MAXLENGTH; ++i)
- if (order[i] > mNumPatterns) mNumPatterns = order[i];
- mNumPatterns++;
-
- // Read patterns
- mPatterns = new unsigned char[mPatternLength * mNumPatterns];
- source.read(mPatterns.getPtr(), mPatternLength * mNumPatterns);
- memoryUse += mPatternLength * mNumPatterns;
-
- ModNote* destPtr = (ModNote*)mPatterns.getPtr();
- unsigned char* srcPtr = mPatterns;
- for (unsigned i = 0; i < mPatternLength * mNumPatterns / 4; ++i)
- {
- unsigned short period = ((srcPtr[0] & 0x0f) << 8) | srcPtr[1];
- unsigned char note = 0, instrument, command;
- if (period)
- {
- int findNote;
- int offset = M_MAX_INT;
-
- for (findNote = 0; findNote < 96; ++findNote)
- {
- if (abs(period - (sPeriodTable[0][findNote % 12] >> (findNote / 12))) < offset)
- {
- note = findNote + 1;
- offset = abs(period - (sPeriodTable[0][findNote % 12] >> (findNote / 12)));
- }
- }
- }
- instrument = (srcPtr[0] & 0xf0) | ((srcPtr[2] & 0xf0) >> 4);
- command = srcPtr[2] & 0x0f;
- destPtr->mNote = note;
- destPtr->mInstrNum = instrument;
- destPtr->mCommand = command;
- srcPtr += 4;
- destPtr++;
- }
- // Load samples
- unsigned char *modInstr = &mInfo[MOD_INSTROFFSET];
- for (unsigned i = 0; i < MOD_INSTRUMENTS; ++i)
- {
- ModInstrument instr;
- memoryUse += sizeof instr;
-
- int length, repeat, end;
- bool looped = false;
-
- length = ((modInstr[22] << 8) | (modInstr[23])) << 1;
- repeat = ((modInstr[26] << 8) | (modInstr[27])) << 1;
- end = ((modInstr[28] << 8) | (modInstr[29])) << 1;
- instr.mFineTune = modInstr[24];
- instr.mVolume = modInstr[25];
- if (length)
- {
- if (end > 2)
- {
- looped = true;
- end += repeat;
- if (end > length) end = length;
- }
- else
- end = length;
-
- instr.mSound = new Sound();
- instr.mSound->setSize(length);
- memoryUse += instr.mSound->getMemoryUse();
- source.read(instr.mSound->getStart(), length);
- if (looped)
- instr.mSound->setLoop(repeat, end);
- }
-
- mInstruments.push_back(instr);
- modInstr += 30;
- }
-
- setMemoryUse(memoryUse);
- mLoaded = true;
- }
- void Mod::release()
- {
- stop();
-
- mLoaded = false;
-
- mTracks.clear();
- mInstruments.clear();
-
- mInfo.reset();
- mPatterns.reset();
- }
- void Mod::play(unsigned position)
- {
- if (!mLoaded)
- return;
-
- stop();
-
- if (position >= mLength)
- position = 0;
-
- mPos = position;
- mLine = 0;
- mTickCount = 0;
- mTickTempo = 6;
- mPatternDelay = 0;
- setBpmTempo(125);
-
- setNumChannels(mNumChannels);
-
- for (unsigned i = 0; i < mNumChannels; ++i)
- {
- ModTrack* tptr = &mTracks[i];
- Channel* chptr = mChannels[i];
-
- chptr->setIntPanning(Song::sPanningTable[i & 3]);
- memset(tptr, 0, sizeof(ModInstrument));
- tptr->mInstr = &mInstruments[0];
- }
-
- mPlaying = true;
- if (mAudio)
- mAudio->addSong(this);
- }
- void Mod::updatePlayer()
- {
- // Set new notes or do something else?
- if ((!mTickCount) && (!mPatternDelay))
- {
- ModNote* notePtr;
- unsigned char* order = &mInfo[MOD_ORDEROFFSET];
-
- notePtr = (ModNote*)(mPatterns.getPtr() + order[mPos] * mPatternLength + mLine * mNumChannels * sizeof(ModNote));
- mPatternBreak = false;
- for (unsigned i = 0; i < mNumChannels; ++i)
- {
- ModTrack* 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, effect data etc.
- tptr->mEffect = notePtr->mCommand;
- tptr->mEffectData = notePtr->mData;
- tptr->mNybble1 = notePtr->mData >> 4;
- tptr->mNybble2 = notePtr->mData & 0xf;
- tptr->mNewInstrNum = notePtr->mInstrNum;
-
- // Set sampleoffset here
- if (tptr->mNewInstrNum)
- tptr->mUseSoundOffset = false;
- if (tptr->mEffect == 0x9)
- {
- if (tptr->mEffectData) tptr->mSoundOffset = tptr->mEffectData;
- tptr->mUseSoundOffset = true;
- }
-
- // Start new note if there is one; but check for notedelay
- if ((tptr->mEffect != 0xe) || (tptr->mNybble1 != 0xd) || (tptr->mNybble2 == 0))
- {
- if (tptr->mNewNote) startNewNote(tptr, chptr);
- if (tptr->mNewInstrNum)
- {
- tptr->mInstrNum = tptr->mNewInstrNum - 1;
- tptr->mInstr = &mInstruments[tptr->mInstrNum];
- tptr->mVolume = tptr->mInstr->mVolume;
- chptr->setIntVolume(tptr->mVolume);
- }
- }
-
- // Reset period if not vibrato or toneportamento
- if ((tptr->mEffect < 0x3) || (tptr->mEffect > 0x6))
- {
- tptr->mPeriod = tptr->mBasePeriod;
- }
-
- // Reset volume if not tremolo
- if (tptr->mEffect != 0x7)
- chptr->setIntVolume(tptr->mVolume);
-
- 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:
- chptr->setIntPanning(tptr->mEffectData);
- break;
-
- // Volume slide speed set
- case 0x5:
- case 0x6:
- case 0xa:
- if (tptr->mEffectData)
- {
- tptr->mVolSpeedUp = tptr->mNybble1;
- tptr->mVolSpeedDown = tptr->mNybble2;
- }
- break;
-
- // Pos. jump
- case 0xb:
- mLine = 63;
- mPos = tptr->mEffectData - 1;
- break;
-
- // Set volume
- case 0xc:
- tptr->mVolume = tptr->mEffectData;
- chptr->setIntVolume(tptr->mVolume);
- 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)
- {
- mPlaying = false;
- break;
- }
- if (tptr->mEffectData < 32) mTickTempo = tptr->mEffectData;
- else setBpmTempo(tptr->mEffectData);
- break;
- }
- if (tptr->mPeriod)
- chptr->setIntFrequency(AMIGA_CLOCK / tptr->mPeriod);
-
- notePtr++;
- }
- }
-
- if (mTickCount)
- {
- // If tick isn't 0, update continuous effects
- for (unsigned i = 0; i < mNumChannels; ++i)
- {
- Channel* chptr = mChannels[i];
- ModTrack* tptr = &mTracks[i];
-
- switch (tptr->mEffect)
- {
- // Arpeggio
- case 0x0:
- {
- if (tptr->mEffectData)
- {
- char phase = mTickCount % 3;
- switch (phase)
- {
- unsigned char arpNote;
-
- case 0:
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- case 1:
- arpNote = tptr->mNote + tptr->mNybble1;
- if (arpNote > 95) arpNote = 95;
- tptr->mPeriod = sPeriodTable[tptr->mFineTune][arpNote % 12] >> (arpNote / 12);
- break;
-
- case 2:
- arpNote = tptr->mNote + tptr->mNybble2;
- if (arpNote > 95) arpNote = 95;
- tptr->mPeriod = sPeriodTable[tptr->mFineTune][arpNote % 12] >> (arpNote / 12);
- break;
- }
- }
- }
- break;
-
- // Portamento up
- case 0x1:
- tptr->mBasePeriod -= tptr->mPortaSpeedUp;
- if (tptr->mBasePeriod < 27) tptr->mBasePeriod = 27;
- tptr->mPeriod = tptr->mBasePeriod;
- break;
-
- // Portamento down
- case 0x2:
- tptr->mBasePeriod += tptr->mPortaSpeedDown;
- if (tptr->mBasePeriod > 7256) tptr->mBasePeriod = 7256;
- 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;
- chptr->setIntVolume(tptr->mVolume + ((Song::sVibratoTable[tptr->mTremoloType & 3][tptr->mTremoloPhase] * tptr->mTremoloDepth) >> 4));
- break;
-
- // Volume slide
- case 0xa:
- volumeSlide(tptr, chptr);
- break;
-
- // Extended command
- case 0xe:
- extendedCommand(tptr, chptr);
- break;
- }
- if (tptr->mPeriod)
- chptr->setIntFrequency(AMIGA_CLOCK / tptr->mPeriod);
- }
- }
-
- // Advance song
- mTickCount++;
- if (mTickCount >= mTickTempo)
- {
- mTickCount = 0;
- if (mPatternDelay)
- mPatternDelay--;
- if (!mPatternDelay)
- {
- mLine++;
- if (mLine >= 64)
- {
- mLine = 0;
- mPos++;
- }
- if (mPos >= mLength)
- mPos = 0;
- }
- }
- }
- void Mod::startNewNote(ModTrack* tptr, Channel* chptr)
- {
- // Change instrument if necessary
- if (tptr->mNewInstrNum)
- {
- tptr->mInstrNum = tptr->mNewInstrNum - 1;
- tptr->mInstr = &mInstruments[tptr->mInstrNum];
- }
- tptr->mFineTune = tptr->mInstr->mFineTune;
- if (!(tptr->mVibratoType & 4)) tptr->mVibratoPhase = 0;
- if (!(tptr->mTremoloType & 4)) tptr->mTremoloPhase = 0;
- if ((tptr->mEffect == 0x3) || (tptr->mEffect == 0x5))
- {
- // Toneportamento
- tptr->mTargetPeriod = sPeriodTable[tptr->mFineTune][tptr->mNote % 12] >> (tptr->mNote / 12);
- tptr->mTonePortamento = true;
- }
- else
- {
- // Normal note start
- tptr->mBasePeriod = sPeriodTable[tptr->mFineTune][tptr->mNote % 12] >> (tptr->mNote / 12);
- tptr->mPeriod = tptr->mBasePeriod;
- tptr->mTonePortamento = false;
- if (tptr->mInstr->mSound)
- {
- chptr->playLockless(tptr->mInstr->mSound);
-
- if (tptr->mUseSoundOffset)
- {
- signed char* newPos = tptr->mInstr->mSound->getStart() + (tptr->mSoundOffset << 8);
- if (newPos >= tptr->mInstr->mSound->getEnd())
- {
- if (tptr->mInstr->mSound->isLooped())
- chptr->setPlayPositionLockless(tptr->mInstr->mSound->getRepeat());
- else
- chptr->stopLockless();
- }
- else
- chptr->setPlayPositionLockless(newPos);
- }
- }
- }
- }
- void Mod::extendedCommand(ModTrack* tptr, Channel* chptr)
- {
- switch(tptr->mNybble1)
- {
- // Fine porta up
- case 0x1:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mPortaSpeedUp = tptr->mNybble2;
- tptr->mBasePeriod -= tptr->mPortaSpeedUp;
- if (tptr->mBasePeriod < 27) tptr->mBasePeriod = 27;
- }
- break;
-
- // Fine porta down
- case 0x2:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mPortaSpeedDown = tptr->mNybble2;
- tptr->mBasePeriod += tptr->mPortaSpeedDown;
- if (tptr->mBasePeriod > 7256) tptr->mBasePeriod = 7256;
- }
- 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 - 8) & 15;
- tptr->mBasePeriod = sPeriodTable[tptr->mFineTune][tptr->mNote % 12] >> (tptr->mNote / 12);
- 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;
-
- // Set panning (undocumented)
- case 0x8:
- chptr->setIntPanning((tptr->mNybble2 << 4) | tptr->mNybble2);
- break;
-
- // Retrig
- case 0x9:
- if (tptr->mNybble2)
- {
- if ((!tptr->mNewNote) && (!mTickCount))
- {
- tptr->mRetrigCount = mTickTempo;
- }
- if (tptr->mRetrigCount >= tptr->mNybble2)
- {
- tptr->mRetrigCount = 0;
- startNewNote(tptr, chptr);
- }
- }
- tptr->mRetrigCount++;
- break;
-
- // Notedelay
- case 0xd:
- // Don't start on tick 0 or if there's no note
- if ((!mTickCount) || (!tptr->mNewNote)) break;
- if (mTickCount == tptr->mNybble2)
- {
- startNewNote(tptr, chptr);
- if (tptr->mNewInstrNum)
- {
- tptr->mVolume = tptr->mInstr->mVolume;
- chptr->setIntVolume(tptr->mVolume);
- }
- }
- break;
-
- // Cut note
- case 0xc:
- if (mTickCount == tptr->mNybble2)
- {
- tptr->mVolume = 0;
- chptr->setIntVolume(0);
- }
- break;
-
- // Fine volslide up
- case 0xa:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mVolSpeedUp = tptr->mNybble2;
- tptr->mVolume += tptr->mVolSpeedUp;
- if (tptr->mVolume > 64) tptr->mVolume = 64;
- chptr->setIntVolume(tptr->mVolume);
- }
- break;
-
- // Fine volslide down
- case 0xb:
- if (!mTickCount)
- {
- if (tptr->mNybble2) tptr->mVolSpeedDown = tptr->mNybble2;
- tptr->mVolume -= tptr->mVolSpeedDown;
- if (tptr->mVolume < 0) tptr->mVolume = 0;
- chptr->setIntVolume(tptr->mVolume);
- }
- break;
-
- // Patterndelay
- case 0xe:
- if (!mTickCount)
- mPatternDelay = tptr->mNybble2 + 1;
- break;
- }
- }
- void Mod::tonePortamento(ModTrack* tptr, Channel* chptr)
- {
- if (tptr->mTonePortamento)
- {
- if (tptr->mBasePeriod < tptr->mTargetPeriod)
- {
- tptr->mBasePeriod += tptr->mTonePortaSpeed;
- if (tptr->mBasePeriod >= tptr->mTargetPeriod)
- {
- tptr->mBasePeriod = tptr->mTargetPeriod;
- tptr->mTonePortamento = false;
- }
- }
- if (tptr->mBasePeriod > tptr->mTargetPeriod)
- {
- tptr->mBasePeriod -= tptr->mTonePortaSpeed;
- if (tptr->mBasePeriod <= tptr->mTargetPeriod)
- {
- tptr->mBasePeriod = tptr->mTargetPeriod;
- tptr->mTonePortamento = false;
- }
- }
- tptr->mPeriod = tptr->mBasePeriod;
- if (tptr->mGlissando)
- {
- int offset = M_MAX_INT;
- int sc;
- short bestPeriod = 0;
-
- for (sc = 0; sc < 96; sc++)
- {
- int newOffset = abs(tptr->mPeriod - (sPeriodTable[tptr->mFineTune][sc % 12] >> (sc / 12)));
- if (newOffset < offset)
- {
- bestPeriod = sPeriodTable[tptr->mFineTune][sc % 12] >> (sc / 12);
- offset = newOffset;
- }
- }
- tptr->mPeriod = bestPeriod;
- }
- }
- }
- void Mod::vibrato(ModTrack* tptr, Channel* chptr)
- {
- tptr->mVibratoPhase += tptr->mVibratoSpeed * 4;
- tptr->mPeriod = tptr->mBasePeriod + ((Song::sVibratoTable[tptr->mVibratoType & 3][tptr->mVibratoPhase] * tptr->mVibratoDepth) >> 5);
- if (tptr->mPeriod < 27) tptr->mPeriod = 27;
- if (tptr->mPeriod > 7256) tptr->mPeriod = 7256;
- }
- void Mod::volumeSlide(ModTrack* tptr, Channel* chptr)
- {
- if (tptr->mVolSpeedUp)
- tptr->mVolume += tptr->mVolSpeedUp;
- if (tptr->mVolume < 0) tptr->mVolume = 0;
- if (tptr->mVolSpeedDown)
- tptr->mVolume -= tptr->mVolSpeedDown;
- if (tptr->mVolume > 64) tptr->mVolume = 64;
- chptr->setIntVolume(tptr->mVolume);
- }
|