diff options
author | Norbert Lange | 2009-08-01 23:02:45 +0000 |
---|---|---|
committer | Norbert Lange | 2009-08-01 23:02:45 +0000 |
commit | a28281072d72197526e68a98442df55c9b5918e4 (patch) | |
tree | e06fe4e9c618e78401dcf6b2d29daa53002cd3b0 | |
parent | ebe409058082e50f8377072eedaa7af34d9dc51a (diff) | |
download | scummvm-rg350-a28281072d72197526e68a98442df55c9b5918e4.tar.gz scummvm-rg350-a28281072d72197526e68a98442df55c9b5918e4.tar.bz2 scummvm-rg350-a28281072d72197526e68a98442df55c9b5918e4.zip |
engines/scumm/scumm.cpp: terminate method is pretty redundant - removed
tfmx, player_v4a: refactored Tfmx to allow sharing of resources between 2 instances. Needed changes in player_v4a aswell
svn-id: r42980
-rw-r--r-- | engines/scumm/music.h | 6 | ||||
-rw-r--r-- | engines/scumm/player_v4a.cpp | 70 | ||||
-rw-r--r-- | engines/scumm/player_v4a.h | 4 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 5 | ||||
-rw-r--r-- | sound/mods/tfmx.cpp | 263 | ||||
-rw-r--r-- | sound/mods/tfmx.h | 136 |
6 files changed, 267 insertions, 217 deletions
diff --git a/engines/scumm/music.h b/engines/scumm/music.h index c6555318a9..2fd7c50bce 100644 --- a/engines/scumm/music.h +++ b/engines/scumm/music.h @@ -81,12 +81,6 @@ public: * @return the music timer */ virtual int getMusicTimer() const { return 0; } - - /** - * Terminate the music engine. Called just before the music engine - * is deleted. - */ - virtual void terminate() {} }; } // End of namespace Scumm diff --git a/engines/scumm/player_v4a.cpp b/engines/scumm/player_v4a.cpp index 649f198f70..dabbd5f950 100644 --- a/engines/scumm/player_v4a.cpp +++ b/engines/scumm/player_v4a.cpp @@ -32,10 +32,22 @@ namespace Scumm { -Player_V4A::Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer) - : _vm(scumm), _mixer(mixer), _musicId(), _sfxSlots(), _initState(0), _tfmxMusic(0), _tfmxSfx(0), _musicHandle(), _sfxHandle(), _signal(0) { +Player_V4A::Player_V4A(ScummEngine *scumm, Audio::Mixer *mixer) : + _vm(scumm), + _mixer(mixer), + _tfmxMusic(_mixer->getOutputRate(), true), + _tfmxSfx(_mixer->getOutputRate(), true), + _musicHandle(), + _sfxHandle(), + _musicId(), + _sfxSlots(), + _initState(0), + _signal(0) { + assert(scumm); assert(mixer); + assert(_vm->_game.id == GID_MONKEY_VGA); + _tfmxMusic.setSignalPtr(&_signal, 1); } bool Player_V4A::init() { @@ -44,33 +56,19 @@ bool Player_V4A::init() { Common::File fileMdat; Common::File fileSample; - bool mdatExists = fileMdat.open("music.dat"); - bool sampleExists = fileSample.open("sample.dat"); - - if (mdatExists && sampleExists) { - Audio::Tfmx *play = new Audio::Tfmx(_mixer->getOutputRate(), true); - if (play->load(fileMdat, fileSample)) { - play->setSignalPtr(&_signal, 1); - _tfmxMusic = play; - } else - delete play; - - play = new Audio::Tfmx(_mixer->getOutputRate(), true); - fileMdat.seek(0); - fileSample.seek(0); - if (play->load(fileMdat, fileSample)) { - _tfmxSfx = play; - } else - delete play; + + if (fileMdat.open("music.dat") && fileSample.open("sample.dat")) { + if (_tfmxMusic.load(fileMdat, fileSample)) { + _tfmxSfx.setModuleData(_tfmxMusic); + return true; + } } - return _tfmxMusic != 0; + return false; } Player_V4A::~Player_V4A() { _mixer->stopHandle(_musicHandle); _mixer->stopHandle(_sfxHandle); - delete _tfmxMusic; - delete _tfmxSfx; } void Player_V4A::setMusicVolume(int vol) { @@ -79,13 +77,11 @@ void Player_V4A::setMusicVolume(int vol) { void Player_V4A::stopAllSounds() { debug(5, "player_v4a: stopAllSounds"); - if (_tfmxMusic) { - _tfmxMusic->stopSong(); - _signal = 0; - } + _tfmxMusic.stopSong(); + _signal = 0; _musicId = 0; - if (_tfmxSfx) - _tfmxSfx->stopSong(); + + _tfmxSfx.stopSong(); clearSfxSlots(); } @@ -95,13 +91,13 @@ void Player_V4A::stopSound(int nr) { return; if (nr == _musicId) { _musicId = 0; - _tfmxMusic->stopSong(); + _tfmxMusic.stopSong(); _signal = 0; } else { const int chan = getSfxChan(nr); if (chan != -1) { setSfxSlot(chan, 0); - _tfmxSfx->stopMacroEffect(chan); + _tfmxSfx.stopMacroEffect(chan); } } } @@ -139,10 +135,10 @@ void Player_V4A::startSound(int nr) { debug(3, "player_v4a: play %d: custom %i - %02X", nr, index, type); // start an empty Song so timing is setup - if (_tfmxSfx->getSongIndex() < 0) - _tfmxSfx->doSong(0x18); + if (_tfmxSfx.getSongIndex() < 0) + _tfmxSfx.doSong(0x18); - const int chan = _tfmxSfx->doSfx((uint16)index); + const int chan = _tfmxSfx.doSfx((uint16)index); if (chan >= 0 && chan < ARRAYSIZE(_sfxSlots)) setSfxSlot(chan, nr, type); else @@ -150,20 +146,20 @@ void Player_V4A::startSound(int nr) { // the Tfmx-player newer "ends" the output by itself, so this should be threadsafe if (!_mixer->isSoundHandleActive(_sfxHandle)) - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _tfmxSfx, -1, Audio::Mixer::kMaxChannelVolume, 0, false); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, &_tfmxSfx, -1, Audio::Mixer::kMaxChannelVolume, 0, false); } else { // Song debug(3, "player_v4a: play %d: song %i - %02X", nr, index, type); if (ptr[6] != 0x7F) warning("player_v4a: Song has wrong type"); - _tfmxMusic->doSong(index); + _tfmxMusic.doSong(index); _signal = 2; _musicId = nr; // the Tfmx-player newer "ends" the output by itself, so this should be threadsafe if (!_mixer->isSoundHandleActive(_musicHandle)) - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _tfmxMusic, -1, Audio::Mixer::kMaxChannelVolume, 0, false); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, &_tfmxMusic, -1, Audio::Mixer::kMaxChannelVolume, 0, false); } } diff --git a/engines/scumm/player_v4a.h b/engines/scumm/player_v4a.h index 373e06fe41..5f5fae6b56 100644 --- a/engines/scumm/player_v4a.h +++ b/engines/scumm/player_v4a.h @@ -56,8 +56,8 @@ private: ScummEngine *const _vm; Audio::Mixer *const _mixer; - Audio::Tfmx *_tfmxMusic; - Audio::Tfmx *_tfmxSfx; + Audio::Tfmx _tfmxMusic; + Audio::Tfmx _tfmxSfx; Audio::SoundHandle _musicHandle; Audio::SoundHandle _sfxHandle; diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index b02c3b3346..5e3bd66b0a 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -546,10 +546,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) ScummEngine::~ScummEngine() { Common::clearAllDebugChannels(); - if (_musicEngine) { - _musicEngine->terminate(); - delete _musicEngine; - } + delete _musicEngine; _mixer->stopAll(); diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp index a9adf27a25..e8febe96a4 100644 --- a/sound/mods/tfmx.cpp +++ b/sound/mods/tfmx.cpp @@ -48,7 +48,7 @@ const uint16 Tfmx::noteIntervalls[64] = { 214, 202, 191, 180 }; Tfmx::Tfmx(int rate, bool stereo) -: Paula(stereo, rate), _resource(), _playerCtx() { +: Paula(stereo, rate), _resource(), _resourceSample(), _playerCtx() { _playerCtx.stopWithLastPattern = false; for (int i = 0; i < kNumVoices; ++i) @@ -65,6 +65,7 @@ Tfmx::Tfmx(int rate, bool stereo) } Tfmx::~Tfmx() { + freeResourceData(); } void Tfmx::interrupt() { @@ -131,7 +132,7 @@ void Tfmx::effects(ChannelContext &channel) { // addBegin if (channel.addBeginLength) { channel.sampleStart += channel.addBeginDelta; - Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart)); if (!(--channel.addBeginCount)) { channel.addBeginCount = channel.addBeginLength; channel.addBeginDelta = -channel.addBeginDelta; @@ -215,7 +216,7 @@ void Tfmx::effects(ChannelContext &channel) { void Tfmx::macroRun(ChannelContext &channel) { bool deferWait = channel.deferWait; for (;;) { - const byte *const macroPtr = (byte *)(_resource.getMacroPtr(channel.macroOffset) + channel.macroStep); + const byte *const macroPtr = (byte *)(getMacroPtr(channel.macroOffset) + channel.macroStep); ++channel.macroStep; switch (macroPtr[0]) { @@ -265,7 +266,7 @@ void Tfmx::macroRun(ChannelContext &channel) { case 0x02: // SetBeginn. Parameters: SampleOffset(L) channel.addBeginLength = 0; channel.sampleStart = READ_BE_UINT32(macroPtr) & 0xFFFFFF; - Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart)); continue; case 0x03: // SetLength. Parameters: SampleLength(W) @@ -293,7 +294,7 @@ void Tfmx::macroRun(ChannelContext &channel) { case 0x06: // Jump. Parameters: MacroIndex, MacroStep(W) channel.macroIndex = macroPtr[1] & (kMaxMacroOffsets - 1); - channel.macroOffset = _macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; + channel.macroOffset = _resource->macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; channel.macroStep = READ_BE_UINT16(¯oPtr[2]); channel.macroLoopCount = 0xFF; continue; @@ -357,7 +358,7 @@ void Tfmx::macroRun(ChannelContext &channel) { channel.addBeginLength = channel.addBeginCount = macroPtr[1]; channel.addBeginDelta = (int16)READ_BE_UINT16(¯oPtr[2]); channel.sampleStart += channel.addBeginDelta; - Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart)); continue; case 0x12: // AddLen. Parameters: added Length(W) @@ -379,7 +380,7 @@ void Tfmx::macroRun(ChannelContext &channel) { channel.macroReturnOffset = channel.macroOffset; channel.macroReturnStep = channel.macroStep; - channel.macroOffset = _macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; + channel.macroOffset = _resource->macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)]; channel.macroStep = READ_BE_UINT16(¯oPtr[2]); // TODO: MI does some weird stuff there. Figure out which varioables need to be set continue; @@ -404,7 +405,7 @@ void Tfmx::macroRun(ChannelContext &channel) { warning("Tfmx: Problematic value for sampleloop: %06X", (macroPtr[1] << 16) | temp); channel.sampleStart += temp & 0xFFFE; channel.sampleLen -= (temp / 2) /* & 0x7FFF */; - Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(channel.sampleStart)); + Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart)); Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen); continue; } @@ -412,7 +413,7 @@ void Tfmx::macroRun(ChannelContext &channel) { channel.addBeginLength = 0; channel.sampleStart = 0; channel.sampleLen = 1; - Paula::setChannelSampleStart(channel.paulaChannel, _resource.getSamplePtr(0)); + Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(0)); Paula::setChannelSampleLen(channel.paulaChannel, 1); continue; @@ -501,7 +502,7 @@ startPatterns: bool Tfmx::patternRun(PatternContext &pattern) { for (;;) { - const byte *const patternPtr = (byte *)(_resource.getPatternPtr(pattern.offset) + pattern.step); + const byte *const patternPtr = (byte *)(getPatternPtr(pattern.offset) + pattern.step); ++pattern.step; const byte pattCmd = patternPtr[0]; @@ -538,7 +539,7 @@ bool Tfmx::patternRun(PatternContext &pattern) { continue; case 2: // Jump. Parameters: PatternIndex, PatternStep(W) - pattern.offset = _patternOffset[patternPtr[1]]; + pattern.offset = _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; pattern.step = READ_BE_UINT16(&patternPtr[2]); continue; @@ -570,7 +571,7 @@ bool Tfmx::patternRun(PatternContext &pattern) { pattern.savedOffset = pattern.offset; pattern.savedStep = pattern.step; - pattern.offset = _patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; + pattern.offset = _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; pattern.step = READ_BE_UINT16(&patternPtr[2]); continue; @@ -588,7 +589,7 @@ bool Tfmx::patternRun(PatternContext &pattern) { PatternContext &target = _patternCtx[patternPtr[2] & (kNumChannels - 1)]; target.command = patternPtr[1]; - target.offset = _patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; + target.offset = _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]; target.expose = patternPtr[3]; target.step = 0; target.wait = 0; @@ -623,7 +624,7 @@ bool Tfmx::trackRun(const bool incStep) { ++_trackCtx.posInd; } for (;;) { - const uint16 *const trackData = _resource.getTrackPtr(_trackCtx.posInd); + const uint16 *const trackData = getTrackPtr(_trackCtx.posInd); if (trackData[0] != FROM_BE_16(0xEFFE)) { // 8 commands for Patterns @@ -636,7 +637,7 @@ bool Tfmx::trackRun(const bool incStep) { _patternCtx[i].step = 0; _patternCtx[i].wait = 0; _patternCtx[i].loopCount = 0xFF; - _patternCtx[i].offset = _patternOffset[patNum]; + _patternCtx[i].offset = _resource->patternOffset[patNum]; } _patternCtx[i].command = (uint8)patNum; _patternCtx[i].expose = patCmd & 0xFF; @@ -703,7 +704,7 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, channel.prevNote = channel.note; channel.note = note; channel.macroIndex = param1 & (kMaxMacroOffsets - 1); - channel.macroOffset = _macroOffset[param1 & (kMaxMacroOffsets - 1)]; + channel.macroOffset = _resource->macroOffset[param1 & (kMaxMacroOffsets - 1)]; channel.relVol = (param2 >> 4) & 0xF; channel.fineTune = (int8)param3; @@ -736,128 +737,182 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, } } -bool Tfmx::load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData) { - bool res; +void Tfmx::setModuleData(Tfmx &otherPlayer) { + setModuleData(otherPlayer._resource, otherPlayer._resourceSample.sampleData, otherPlayer._resourceSample.sampleLen, false); +} - assert(0 == _resource.mdatData); - assert(0 == _resource.sampleData); +bool Tfmx::load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData, bool autoDelete) { + MdatResource *mdat = new MdatResource(); + if (loadMdatFile(*mdat, musicData)) { + int8 *sampleDat = 0; + uint32 sampleLen = 0; + if (loadSampleFile(sampleDat, sampleLen, sampleData)) { + setModuleData(mdat, sampleDat, sampleLen, autoDelete); + return true; + } + } + delete[] mdat->mdatAlloc; + delete mdat; + return false; +} - // TODO: Sanity checks if we have a valid TFMX-Module - // TODO: check for Stream-Errors (other than using asserts) +void Tfmx::freeResourceData() { + if (_deleteResource) { + if (_resource) { + delete[] _resource->mdatAlloc; + delete _resource; + } + delete[] _resourceSample.sampleData; + } + _resource = 0; + _resourceSample.sampleData = 0; + _resourceSample.sampleLen = 0; +} - // 0x0000: 10 Bytes Header "TFMX-SONG " - // 0x000A: int16 ? - // 0x000C: int32 ? - musicData.read(_resource.header, 10); - _resource.headerFlags = musicData.readUint16BE(); - _resource.headerUnknown = musicData.readUint32BE(); +void Tfmx::setModuleData(const MdatResource *resource, const int8 *sampleData, uint32 sampleLen, bool autoDelete) { + Common::StackLock lock(_mutex); + // TODO: stop sound and deallocate previous resources + _resource = resource; + _resourceSample.sampleData = sampleData; + _resourceSample.sampleLen = sampleData ? sampleLen : 0; + _deleteResource = autoDelete; +} + +bool Tfmx::loadSampleFile(int8 *&sampleData, uint32 &sampleLen, Common::SeekableReadStream &sampleStream) { + assert(!sampleData); + sampleData = 0; + sampleLen = 0; + + const int32 sampleSize = sampleStream.size(); + if (sampleSize < 4) { + warning("Tfmx: Cant load Samplefile"); + return false; + } + + int8 *sampleAlloc = new int8[sampleSize]; + if (!sampleAlloc) { + warning("Tfmx: Could not allocate Memory: %dKB", sampleSize / 1024); + return false; + } + + if (sampleStream.read(sampleAlloc, sampleSize) == (uint32)sampleSize) { + sampleAlloc[0] = sampleAlloc[1] = sampleAlloc[2] = sampleAlloc[3] = 0; + sampleData = sampleAlloc; + sampleLen = sampleSize; + } else { + delete sampleAlloc; + warning("Tfmx: Encountered IO-Error"); + return false; + } + return true; +} + +bool Tfmx::loadMdatFile(MdatResource &resource, Common::SeekableReadStream &musicData) { + assert(!resource.mdatAlloc); - // This might affect timing - // bool isPalModule = (_resource.headerFlags & 2) != 0; + resource.mdatAlloc = 0; + resource.mdatData = 0; + resource.mdatLen = 0; + bool hasHeader = false; + const int32 mdatSize = musicData.size(); + if (mdatSize >= 0x200) { + byte buf[16] = { 0 }; + // 0x0000: 10 Bytes Header "TFMX-SONG " + musicData.read(buf, 10); + hasHeader = memcmp(buf, "TFMX-SONG ", 10) == 0; + } + + if (!hasHeader) { + warning("Tfmx: File is not a Tfmx Module"); + return false; + } + + // 0x000A: int16 flags + resource.headerFlags = musicData.readUint16BE(); + // 0x000C: int32 ? // 0x0010: 6*40 Textfield - musicData.read(_resource.textField, 6 * 40); + musicData.skip(4 + 6 * 40); /* 0x0100: Songstart x 32*/ for (int i = 0; i < kNumSubsongs; ++i) - _subsong[i].songstart = musicData.readUint16BE(); - + resource.subsong[i].songstart = musicData.readUint16BE(); /* 0x0140: Songend x 32*/ for (int i = 0; i < kNumSubsongs; ++i) - _subsong[i].songend = musicData.readUint16BE(); - + resource.subsong[i].songend = musicData.readUint16BE(); /* 0x0180: Tempo x 32*/ for (int i = 0; i < kNumSubsongs; ++i) - _subsong[i].tempo = musicData.readUint16BE(); + resource.subsong[i].tempo = musicData.readUint16BE(); /* 0x01c0: unused ? */ musicData.skip(16); /* 0x01d0: trackstep, pattern data p, macro data p */ - uint32 offTrackstep = musicData.readUint32BE(); - uint32 offPatternP = musicData.readUint32BE(); - uint32 offMacroP = musicData.readUint32BE(); - _resource.sfxTableOffset = 0x200; - bool getSfxIndex = false; + const uint32 offTrackstep = musicData.readUint32BE(); + uint32 offPatternP, offMacroP; // This is how MI`s TFMX-Player tests for unpacked Modules. - if (offTrackstep == 0) { - offTrackstep = 0x600 + 0x200; + if (!offTrackstep) { // unpacked File + resource.trackstepOffset = 0x600 + 0x200; offPatternP = 0x200 + 0x200; offMacroP = 0x400 + 0x200; - getSfxIndex = true; - _resource.sfxTableOffset = 0x5FC; + } else { // packed File + resource.trackstepOffset = offTrackstep; + offPatternP = musicData.readUint32BE(); + offMacroP = musicData.readUint32BE(); } - _resource.trackstepOffset = offTrackstep; + // End of basic header, check if everything worked ok + if (musicData.err()) { + warning("Tfmx: Encountered IO-Error"); + return false; + } + + // TODO: if a File is packed it could have for Ex only 2 Patterns/Macros + // the following loops could then read beyond EOF. + // To correctly handle this it would be necessary to sort the pointers and + // figure out the number of Macros/Patterns + // We could also analyze pointers if they are correct offsets, + // so that accesses can be unchecked later // Read in pattern starting offsets musicData.seek(offPatternP); for (int i = 0; i < kMaxPatternOffsets; ++i) - _patternOffset[i] = musicData.readUint32BE(); - - res = musicData.err(); - assert(!res); + resource.patternOffset[i] = musicData.readUint32BE(); - if (getSfxIndex) - _resource.sfxTableOffset = _patternOffset[127]; + // use last PatternOffset (stored at 0x5FC in mdat) if unpacked File + // or fixed offset 0x200 if packed + resource.sfxTableOffset = !offTrackstep ? resource.patternOffset[127] : 0x200; // Read in macro starting offsets musicData.seek(offMacroP); for (int i = 0; i < kMaxMacroOffsets; ++i) - _macroOffset[i] = musicData.readUint32BE(); + resource.macroOffset[i] = musicData.readUint32BE(); - res = musicData.err(); - assert(!res); - - // Read in whole mdat-file - int32 size = musicData.size(); - assert(size != -1); - // TODO: special routine if size = -1? - - _resource.mdatData = new byte[size]; - assert(_resource.mdatData); - _resource.mdatLen = size; - musicData.seek(0); - musicData.read(_resource.mdatData, size); + // Read in mdat-file + // TODO: we can skip everything thats already stored in the resource-structure. + const int32 mdatOffset = 0x200; // 0x200 is very conservative + const uint32 allocSize = (uint32)mdatSize - mdatOffset; - res = musicData.err(); - assert(!res); - musicData.readByte(); - res = musicData.eos(); - assert(res); - - - // TODO: It would be possible to analyze the pointers and be able to - // seperate the file in trackstep, patterns and macro blocks - // Modules could do weird stuff like having those blocks mixed though. - // TODO: Analyze pointers if they are correct offsets, - // so that accesses can be unchecked later - - // Read in whole sample-file - size = sampleData.size(); - assert(size >= 4); - assert(size != -1); - // TODO: special routine if size = -1? - - _resource.sampleData = new byte[size]; - assert(_resource.sampleData); - _resource.sampleLen = size; - sampleData.seek(0); - sampleData.read(_resource.sampleData, size); - for (int i = 0; i < 4; ++i) - _resource.sampleData[i] = 0; - - res = sampleData.err(); - assert(!res); - sampleData.readByte(); - res = sampleData.eos(); - assert(res); + byte *mdatAlloc = new byte[allocSize]; + if (!mdatAlloc) { + warning("Tfmx: Could not allocate Memory: %dKB", allocSize / 1024); + return false; + } + musicData.seek(mdatOffset); + if (musicData.read(mdatAlloc, allocSize) == allocSize) { + resource.mdatAlloc = mdatAlloc; + resource.mdatData = mdatAlloc - mdatOffset; + resource.mdatLen = mdatSize; + } else { + delete mdatAlloc; + warning("Tfmx: Encountered IO-Error"); + return false; + } return true; } - void Tfmx::doMacro(int note, int macro, int relVol, int finetune, int channelNo) { assert(0 <= macro && macro < kMaxMacroOffsets); assert(0 <= note && note < 0xC0); @@ -901,11 +956,11 @@ void Tfmx::doSong(int songPos, bool stopAudio) { _playerCtx.song = (int8)songPos; _trackCtx.loopCount = -1; - _trackCtx.startInd = _trackCtx.posInd = _subsong[songPos].songstart; - _trackCtx.stopInd = _subsong[songPos].songend; + _trackCtx.startInd = _trackCtx.posInd = _resource->subsong[songPos].songstart; + _trackCtx.stopInd = _resource->subsong[songPos].songend; - const bool palFlag = (_resource.headerFlags & 2) != 0; - const uint16 tempo = _subsong[songPos].tempo; + const bool palFlag = (_resource->headerFlags & 2) != 0; + const uint16 tempo = _resource->subsong[songPos].tempo; uint16 ciaIntervall; if (tempo >= 0x10) { ciaIntervall = (uint16)(kCiaBaseInterval / tempo); @@ -925,7 +980,7 @@ int Tfmx::doSfx(uint16 sfxIndex, bool unlockChannel) { assert(0 <= sfxIndex && sfxIndex < 128); Common::StackLock lock(_mutex); - const byte *sfxEntry = _resource.getSfxPtr(sfxIndex); + const byte *sfxEntry = getSfxPtr(sfxIndex); if (sfxEntry[0] == 0xFB) { // custompattern const uint8 patCmd = sfxEntry[2]; diff --git a/sound/mods/tfmx.h b/sound/mods/tfmx.h index f720d727d6..3f3d982ba6 100644 --- a/sound/mods/tfmx.h +++ b/sound/mods/tfmx.h @@ -28,16 +28,6 @@ #include "sound/mods/paula.h" -namespace { -#ifndef NDEBUG -inline void boundaryCheck(const void *bufStart, size_t bufLen, const void *address, size_t accessLen = 1) { - assert(bufStart <= address && (const byte *)address + accessLen <= (const byte *)bufStart + bufLen); -} -#else -inline void boundaryCheck(const void *, size_t, void *, size_t = 1) {} -#endif -} - namespace Audio { class Tfmx : public Paula { @@ -49,12 +39,18 @@ public: void doSong(int songPos, bool stopAudio = false); int doSfx(uint16 sfxIndex, bool unlockChannel = false); void doMacro(int note, int macro, int relVol = 0, int finetune = 0, int channelNo = 0); - bool load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData); int getTicks() const { return _playerCtx.tickCount; } int getSongIndex() const { return _playerCtx.song; } void setSignalPtr(uint16 *ptr, uint16 numSignals) { _playerCtx.signal = ptr; _playerCtx.numSignals = numSignals; } void stopMacroEffect(int channel); + struct MdatResource; + bool load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData, bool autoDelete = true); + void setModuleData(Tfmx &otherPlayer); + void setModuleData(const MdatResource *resource, const int8 *sampleData, uint32 sampleLen, bool autoDelete = true); + static bool loadMdatFile(MdatResource &resource, Common::SeekableReadStream &musicData); + static bool loadSampleFile(int8 *&sampleData, uint32 &sampleLen, Common::SeekableReadStream &sampleStream); + protected: void interrupt(); @@ -64,71 +60,46 @@ private: static const uint16 noteIntervalls[64]; - struct Resource { - uint32 trackstepOffset; //!< Offset in mdat - uint32 sfxTableOffset; +public: // TODO change this to private somehow= + struct MdatResource { + const byte *mdatAlloc; //!< allocated Block of Memory + const byte *mdatData; //!< Start of mdat-File, might point before mdatAlloc to correct Offset + uint32 mdatLen; - byte *mdatData; //!< Currently the whole mdat-File - byte *sampleData; //!< Currently the whole sample-File - - uint32 mdatLen; - uint32 sampleLen; - - byte header[10]; uint16 headerFlags; - uint32 headerUnknown; - char textField[6 * 40]; - - const byte *getSfxPtr(uint16 index = 0) { - byte *sfxPtr = (byte *)(mdatData + sfxTableOffset + index * 8); - - boundaryCheck(mdatData, mdatLen, sfxPtr, 8); - return sfxPtr; - } - - const uint16 *getTrackPtr(uint16 trackstep = 0) { - uint16 *trackData = (uint16 *)(mdatData + trackstepOffset + 16 * trackstep); +// uint32 headerUnknown; +// char textField[6 * 40]; - boundaryCheck(mdatData, mdatLen, trackData, 16); - return trackData; - } + struct Subsong { + uint16 songstart; //!< Index in Trackstep-Table + uint16 songend; //!< Last index in Trackstep-Table + uint16 tempo; + } subsong[kNumSubsongs]; - const uint32 *getPatternPtr(uint32 offset) { - uint32 *pattData = (uint32 *)(mdatData + offset); - - boundaryCheck(mdatData, mdatLen, pattData, 4); - return pattData; - } + uint32 trackstepOffset; //!< Offset in mdat + uint32 sfxTableOffset; - const uint32 *getMacroPtr(uint32 offset) { - uint32 *macroData = (uint32 *)(mdatData + offset); + uint32 patternOffset[kMaxPatternOffsets]; //!< Offset in mdat + uint32 macroOffset[kMaxMacroOffsets]; //!< Offset in mdat - boundaryCheck(mdatData, mdatLen, macroData, 4); - return macroData; + void boundaryCheck(const void *address, size_t accessLen = 1) const { + assert(mdatAlloc <= address && (const byte *)address + accessLen <= (const byte *)mdatData + mdatLen); } + }; - const int8 *getSamplePtr(const uint32 offset) { - int8 *sample = (int8 *)(sampleData + offset); +private: + const MdatResource *_resource; - boundaryCheck(sampleData, sampleLen, sample, 2); - return sample; - } - Resource() : mdatData(), mdatLen(), sampleData(), sampleLen() {} + struct SampleResource { + const int8 *sampleData; //!< The whole sample-File + uint32 sampleLen; - ~Resource() { - delete[] mdatData; - delete[] sampleData; + void boundaryCheck(const void *address, size_t accessLen = 2) const { + assert(sampleData <= address && (const byte *)address + accessLen <= (const byte *)sampleData + sampleLen); } - } _resource; - - uint32 _patternOffset[kMaxPatternOffsets]; //!< Offset in mdat - uint32 _macroOffset[kMaxMacroOffsets]; //!< Offset in mdat + } _resourceSample; - struct Subsong { - uint16 songstart; //!< Index in Trackstep-Table - uint16 songend; //!< Last index in Trackstep-Table - uint16 tempo; - } _subsong[kNumSubsongs]; + bool _deleteResource; struct ChannelContext { byte paulaChannel; @@ -225,6 +196,41 @@ private: bool stopWithLastPattern; //!< hack to automatically stop the whole player if no Pattern is running } _playerCtx; + const byte *getSfxPtr(uint16 index = 0) const { + const byte *sfxPtr = (byte *)(_resource->mdatData + _resource->sfxTableOffset + index * 8); + + _resource->boundaryCheck(sfxPtr, 8); + return sfxPtr; + } + + const uint16 *getTrackPtr(uint16 trackstep = 0) const { + const uint16 *trackData = (uint16 *)(_resource->mdatData + _resource->trackstepOffset + 16 * trackstep); + + _resource->boundaryCheck(trackData, 16); + return trackData; + } + + const uint32 *getPatternPtr(uint32 offset) const { + const uint32 *pattData = (uint32 *)(_resource->mdatData + offset); + + _resource->boundaryCheck(pattData, 4); + return pattData; + } + + const uint32 *getMacroPtr(uint32 offset) const { + const uint32 *macroData = (uint32 *)(_resource->mdatData + offset); + + _resource->boundaryCheck(macroData, 4); + return macroData; + } + + const int8 *getSamplePtr(const uint32 offset) const { + const int8 *sample = _resourceSample.sampleData + offset; + + _resourceSample.boundaryCheck(sample, 2); + return sample; + } + static void initMacroProgramm(ChannelContext &channel) { channel.macroStep = 0; channel.macroWait = 0; @@ -293,6 +299,8 @@ private: } } + + void freeResourceData(); void effects(ChannelContext &channel); void macroRun(ChannelContext &channel); void advancePatterns(); |